com.googlecode.mp4parser.boxes.cenc.CencDecryptingSampleList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of isoparser Show documentation
Show all versions of isoparser Show documentation
A generic parser and writer for all ISO 14496 based files (MP4, Quicktime, DCF, PDCF, ...)
The newest version!
package com.googlecode.mp4parser.boxes.cenc;
import com.googlecode.mp4parser.authoring.Sample;
import com.googlecode.mp4parser.authoring.SampleImpl;
import com.googlecode.mp4parser.util.RangeStartMap;
import com.mp4parser.iso23001.part7.CencSampleAuxiliaryDataFormat;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.AbstractList;
import java.util.List;
import static com.googlecode.mp4parser.util.CastUtils.l2i;
public class CencDecryptingSampleList extends AbstractList {
List sencInfo;
RangeStartMap keys = new RangeStartMap();
List parent;
String encryptionAlgo;
public CencDecryptingSampleList(SecretKey secretKey, List parent, List sencInfo) {
this(new RangeStartMap(0, secretKey), parent, sencInfo, "cenc");
}
public CencDecryptingSampleList(
RangeStartMap keys,
List parent, List sencInfo,
String encryptionAlgo) {
this.sencInfo = sencInfo;
this.keys = keys;
this.parent = parent;
this.encryptionAlgo = encryptionAlgo;
}
Cipher getCipher(SecretKey sk, byte[] iv) {
byte[] fullIv = new byte[16];
System.arraycopy(iv, 0, fullIv, 0, iv.length);
// The IV
try {
if ("cenc".equals(encryptionAlgo)) {
Cipher c = Cipher.getInstance("AES/CTR/NoPadding");
c.init(Cipher.DECRYPT_MODE, sk, new IvParameterSpec(fullIv));
return c;
} else if ("cbc1".equals(encryptionAlgo)) {
Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
c.init(Cipher.DECRYPT_MODE, sk, new IvParameterSpec(fullIv));
return c;
} else {
throw new RuntimeException("Only cenc & cbc1 is supported as encryptionAlgo");
}
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
}
@Override
public Sample get(int index) {
if (keys.get(index) != null) {
Sample encSample = parent.get(index);
final ByteBuffer encSampleBuffer = encSample.asByteBuffer();
encSampleBuffer.rewind();
final ByteBuffer decSampleBuffer = ByteBuffer.allocate(encSampleBuffer.limit());
final CencSampleAuxiliaryDataFormat sencEntry = sencInfo.get(index);
Cipher cipher = getCipher(keys.get(index), sencEntry.iv);
try {
if (sencEntry.pairs != null && sencEntry.pairs.length > 0) {
for (CencSampleAuxiliaryDataFormat.Pair pair : sencEntry.pairs) {
final int clearBytes = pair.clear();
final int encrypted = l2i(pair.encrypted());
byte[] clears = new byte[clearBytes];
encSampleBuffer.get(clears);
decSampleBuffer.put(clears);
if (encrypted > 0) {
byte[] encs = new byte[encrypted];
encSampleBuffer.get(encs);
final byte[] decr = cipher.update(encs);
decSampleBuffer.put(decr);
}
}
if (encSampleBuffer.remaining() > 0) {
System.err.println("Decrypted sample but still data remaining: " + encSample.getSize());
}
decSampleBuffer.put(cipher.doFinal());
} else {
byte[] fullyEncryptedSample = new byte[encSampleBuffer.limit()];
encSampleBuffer.get(fullyEncryptedSample);
if ("cbc1".equals(encryptionAlgo)) {
int encryptedLength = fullyEncryptedSample.length / 16 * 16;
decSampleBuffer.put(cipher.doFinal(fullyEncryptedSample, 0, encryptedLength));
decSampleBuffer.put(fullyEncryptedSample, encryptedLength, fullyEncryptedSample.length - encryptedLength);
} else if ("cenc".equals(encryptionAlgo)) {
decSampleBuffer.put(cipher.doFinal(fullyEncryptedSample));
}
}
encSampleBuffer.rewind();
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(e);
} catch (BadPaddingException e) {
throw new RuntimeException(e);
}
decSampleBuffer.rewind();
return new SampleImpl(decSampleBuffer);
} else {
return parent.get(index);
}
}
@Override
public int size() {
return parent.size();
}
}