fixed building drm key url and AES-128 decoding
This commit is contained in:
@@ -70,7 +70,7 @@ public class M3UDownloader implements ITrackDownloader {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
VKM3UParser parser = new VKM3UParser(payload);
|
||||
VKM3UParser parser = new VKM3UParser(track.D.substring(0,track.D.lastIndexOf("/")+1),payload);
|
||||
AtomicInteger progress = new AtomicInteger(0);
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>(parser.mTransportStreams.size());
|
||||
|
||||
@@ -88,19 +88,23 @@ public class M3UDownloader implements ITrackDownloader {
|
||||
final var ts=tses.get(i);
|
||||
final var filename=i+".ts";
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
InputStream mediaIs,keyPubIs;
|
||||
mediaIs=keyPubIs=null;
|
||||
try {
|
||||
InputStream is = IOUtils.openStream(ts.getMediaSegmentUri());
|
||||
mediaIs=IOUtils.openStream(ts.getMediaSegmentUri());
|
||||
byte[] content;
|
||||
if (ts.needDecoding()) {
|
||||
String key = IOUtils.readAllLines(IOUtils.openStream(ts.getKeyURL()));
|
||||
content = IOUtils.decodeStream(is, key);
|
||||
keyPubIs=IOUtils.openStream(ts.getKeyURL());
|
||||
content=IOUtils.decodeStream(mediaIs,IOUtils.readFully(keyPubIs));
|
||||
} else {
|
||||
content = IOUtils.readFully(is);
|
||||
content=IOUtils.readFully(mediaIs);
|
||||
}
|
||||
File tsDump = new File(tsesDir,filename);
|
||||
IOUtils.writeToFile(tsDump, content);
|
||||
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()));
|
||||
callback.onSizeReceived((long) content.length * tses.size(), parser.mHeapSize);
|
||||
mediaIs.close();
|
||||
keyPubIs.close();
|
||||
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException |
|
||||
InvalidAlgorithmParameterException | InvalidKeyException e) {
|
||||
callback.onFailure();
|
||||
|
||||
@@ -53,19 +53,19 @@ public class VKM3UParser {
|
||||
final private String mData;
|
||||
final public List<TransportStream> mTransportStreams = new ArrayList<>();
|
||||
|
||||
public VKM3UParser(String data) {
|
||||
public VKM3UParser(String baseUri,String data) {
|
||||
mData=data;
|
||||
init();
|
||||
init(baseUri);
|
||||
}
|
||||
|
||||
public static boolean isTS(String str) {
|
||||
return str.endsWith(".ts")||str.endsWith(".tp")||str.endsWith(".mpeg-ts")||str.endsWith(".m2ts");
|
||||
return str.matches(".+\\.ts.*");
|
||||
}
|
||||
|
||||
private void init()
|
||||
private void init(String baseUri)
|
||||
{
|
||||
if(TextUtils.isEmpty(mData))throw new NullPointerException("mData==null");
|
||||
final var scanner=new Scanner(mData);
|
||||
if(TextUtils.isEmpty(mData))throw new NullPointerException("mData==null");
|
||||
final var scanner=new Scanner(mData);
|
||||
var line=scanner.nextLine();
|
||||
if(!"#EXTM3U".equals(line))throw new IllegalStateException(String.format("Unknown initial M3U tag: %s",line));
|
||||
//indicators for EXT-X-KEY and EXTINF tags
|
||||
@@ -75,9 +75,7 @@ public class VKM3UParser {
|
||||
* VK follows own URI attribute for EXT-X-KEY tag.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.2.4">EXT-X-KEY</a>
|
||||
**/
|
||||
String keyUri;
|
||||
String baseUri;//At least one media segment must be encrypted to get the base uri
|
||||
keyUri=baseUri="";
|
||||
String keyUri="";
|
||||
while(scanner.hasNextLine())
|
||||
{
|
||||
line=scanner.nextLine();
|
||||
@@ -105,12 +103,12 @@ public class VKM3UParser {
|
||||
else if(line.startsWith("#EXT-X-KEY:"))
|
||||
{
|
||||
var substr=line.substring(11);
|
||||
if((aes128=substr.startsWith("METHOD=AES-128")))
|
||||
if((aes128=substr.contains("METHOD=AES-128")))
|
||||
{
|
||||
substr=substr.substring(20,substr.length()-1);
|
||||
if(!substr.startsWith("http"))throw new IllegalStateException(String.format("Failed to parse URI: %s",substr));
|
||||
keyUri=substr;
|
||||
baseUri=substr.substring(0,substr.lastIndexOf('/')+1);
|
||||
substr=substr.substring(substr.indexOf('"')+1,substr.lastIndexOf('"'));
|
||||
//TODO: supposed endpoint
|
||||
keyUri=substr.startsWith("http")?substr:baseUri+substr;
|
||||
Log.d("keyURL",keyUri);
|
||||
}
|
||||
}
|
||||
else if(line.startsWith("#EXTINF"))
|
||||
@@ -127,6 +125,5 @@ public class VKM3UParser {
|
||||
else throw new RuntimeException(String.format("Failed to parse: %s",line));
|
||||
mHeapSize+=line.getBytes().length;
|
||||
}
|
||||
if(baseUri.isEmpty())throw new NullPointerException("baseUri==null");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,16 @@ import java.util.Arrays;
|
||||
public class IOUtils {
|
||||
public static final int BUFFER_SIZE = 8192;
|
||||
|
||||
public static byte[] decodeStream(InputStream encIs, String keyURL)
|
||||
public static byte[] decodeStream(InputStream encIs,byte[] aesKey)
|
||||
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException {
|
||||
CipherInputStream cip = new CipherInputStream(encIs, getCipher(keyURL));
|
||||
CipherInputStream cip = new CipherInputStream(encIs, getCipher(aesKey));
|
||||
return readFully(cip);
|
||||
}
|
||||
|
||||
public static Cipher getCipher(String key)
|
||||
public static Cipher getCipher(byte[] aesKey)
|
||||
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
Key keySpec = new SecretKeySpec(key.getBytes(), "AES");
|
||||
// bypassing ecb
|
||||
Key keySpec = new SecretKeySpec(aesKey, "AES");
|
||||
byte[] iv = new byte[16];
|
||||
Arrays.fill(iv, (byte) 0x0);
|
||||
IvParameterSpec ivps = new IvParameterSpec(iv);
|
||||
|
||||
Reference in New Issue
Block a user