Skip to content
This repository has been archived by the owner on Nov 22, 2022. It is now read-only.

Commit

Permalink
Iv hex encoding (#51)
Browse files Browse the repository at this point in the history
* Correct writing of hexadecimal values

Because WriteUtil.writeHexadecimal used Integer.toHexString which
converts each byte into an integer and then writes that integer using
the minimum required number of hexadecimal digits results would vary
and negative bytes would be written using 8 hexadecimal digits with
the first 6 being ffffff and positive bytes between 0 and 15 would
only be written using 1 hexadecimal digit. This would cause the IV
in EXT-X-KEY tags to be corrupted.

Using String.format("%02x", b) instead means all bytes will be written
correctly. They won't take up more than 2 characters since no
integer-conversion is performed and if only 1 digit is required they
will be zero-padded.

* Added test for WriteUtil#writeHexadecimal

* Correct parsing of hexadecimal values

* Fixed failing testEXT_X_KEY

The IV was too short and the expected value was wrong
  • Loading branch information
Raniz85 authored and sunglee413 committed Oct 20, 2017
1 parent 0c3d465 commit 7665c2a
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 9 deletions.
13 changes: 8 additions & 5 deletions src/main/java/com/iheartradio/m3u8/ParseUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static <T extends Enum<T>> T parseEnum(String string, Class<T> enumType,
throw ParseException.create(ParseExceptionType.NOT_JAVA_ENUM, tag, string);
}
}

public static String parseDateTime(String string, String tag) throws ParseException {
Matcher matcher = Constants.EXT_X_PROGRAM_DATE_TIME_PATTERN.matcher(string);

Expand All @@ -50,17 +50,20 @@ public static List<Byte> parseHexadecimal(String hexString, String tag) throws P

if (matcher.matches()) {
String valueString = matcher.group(1);
if (valueString.length() % 2 != 0) {
throw ParseException.create(ParseExceptionType.INVALID_HEXADECIMAL_STRING, tag, hexString);
}

for (char c : valueString.toCharArray()) {
bytes.add(hexCharToByte(c));
for (int i = 0; i < valueString.length(); i += 2) {
bytes.add((byte)(Short.parseShort(valueString.substring(i, i+2), 16) & 0xFF));
}

return bytes;
} else {
throw ParseException.create(ParseExceptionType.INVALID_HEXADECIMAL_STRING, tag, hexString);
}
}

private static byte hexCharToByte(char hex) {
if (hex >= 'A') {
return (byte) ((hex & 0xF) + 9);
Expand Down Expand Up @@ -185,7 +188,7 @@ public static List<Attribute> parseAttributeList(String line, String tag) throws
//Even Apple playlists have sometimes spaces after a ,
final String name = string.substring(0, separator).trim();
final String value = string.substring(separator + 1);

if (name.isEmpty()) {
throw ParseException.create(ParseExceptionType.MISSING_ATTRIBUTE_NAME, tag, attributes.toString());
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/iheartradio/m3u8/WriteUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static String writeHexadecimal(List<Byte> hex) {
StringBuilder builder = new StringBuilder(hex.size() + prefix.length());
builder.append(prefix);
for(Byte b : hex) {
builder.append(Integer.toHexString(b));
builder.append(String.format("%02x", b));
}
return builder.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void testEXT_X_KEY() throws Exception {
final String line = "#" + tag +
":METHOD=AES-128" +
",URI=\"" + uri + "\"" +
",IV=0x1234abcd5678EF90" +
",IV=0x1234abcd5678EF90aabbccddeeff0011" +
",KEYFORMAT=\"" + format + "\"" +
",KEYFORMATVERSIONS=\"1/2/3\"";

Expand All @@ -58,8 +58,10 @@ public void testEXT_X_KEY() throws Exception {
assertEquals(uri, encryptionData.getUri());

assertEquals(
Arrays.asList((byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 10, (byte) 11, (byte) 12, (byte) 13,
(byte) 5, (byte) 6, (byte) 7, (byte) 8, (byte) 14, (byte) 15, (byte) 9, (byte) 0),
Arrays.asList((byte) 0x12, (byte) 0x34, (byte) 0xAB, (byte) 0xCD,
(byte) 0x56, (byte) 0x78, (byte) 0xEF, (byte) 0x90,
(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD,
(byte) 0xEE, (byte) 0xFF, (byte) 0x00, (byte) 0x11),
encryptionData.getInitializationVector());

assertEquals(format, encryptionData.getKeyFormat());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2017, Spiideo
*/

package com.iheartradio.m3u8;

import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

/**
* @author Raniz
* @since 02/08/17.
*/
@RunWith(Parameterized.class)
public class ParseUtilParseHexadecimalTest {

@Parameterized.Parameters(name = "{index}: {1}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][]{
{Arrays.asList((byte) 0), "0x00"},
{Arrays.asList((byte) 1), "0x01"},
{Arrays.asList((byte) -1), "0xff"},
{Arrays.asList((byte) -16), "0xf0"},
{Arrays.asList((byte) 0, (byte) 1), "0x0001"},
{Arrays.asList((byte) 1, (byte) 1), "0x0101"},
{Arrays.asList((byte) -1, (byte) -1), "0xffff"},
{Arrays.asList((byte) -121, (byte) -6), "0x87fa"},
{Arrays.asList((byte) 75, (byte) 118), "0x4b76"},
});
}

private final List<Byte> expected;
private final String input;

public ParseUtilParseHexadecimalTest(final List<Byte> expected, final String input) {
this.expected = expected;
this.input = input;
}

@Test
public void parseHexadecimal() throws Exception {
Assert.assertEquals(expected, ParseUtil.parseHexadecimal(input, ""));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2017, Spiideo
*/

package com.iheartradio.m3u8;

import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

/**
* @author Raniz
* @since 02/08/17.
*/
@RunWith(Parameterized.class)
public class WriteUtilWriteHexadecimalTest {

@Parameterized.Parameters(name = "{index}: {1}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][]{
{Arrays.asList((byte) 0), "0x00"},
{Arrays.asList((byte) 1), "0x01"},
{Arrays.asList((byte) -1), "0xff"},
{Arrays.asList((byte) -16), "0xf0"},
{Arrays.asList((byte) 0, (byte) 1), "0x0001"},
{Arrays.asList((byte) 1, (byte) 1), "0x0101"},
{Arrays.asList((byte) -1, (byte) -1), "0xffff"},
{Arrays.asList((byte) -121, (byte) -6), "0x87fa"},
{Arrays.asList((byte) 75, (byte) 118), "0x4b76"},
});
}

private final List<Byte> input;
private final String expected;

public WriteUtilWriteHexadecimalTest(final List<Byte> input, final String expected) {
this.input = input;
this.expected = expected;
}

@Test
public void writeHexadecimal() throws Exception {
Assert.assertEquals(expected, WriteUtil.writeHexadecimal(input));
}

}

0 comments on commit 7665c2a

Please sign in to comment.