我需要支持ECB加密以实现向后兼容性(我知道ecb是不安全的,但我仍然需要这样做。)。我正在使用exoplayer,因此我需要进行自定义com.google.android.exoplayer.upstream.DataSource
实现。我收到了WRONG_FINAL_BLOCK_LENGTH错误,我很难克服这个错误。
重要变量:
public static final String ECB_TRANSFORMATION = "AES/ECB/PKCS7Padding";
public static final String ENCRYPTION_ALGORITHM = "AES";
public static final String ECB_ENCRYPTION = "ECB";
onCreate of my fragment(可能不重要):
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startPosition = getArguments().getLong(BundleConstants.MEDIA_POSITION, 0);
boolean isAudioOnly = ContentHelper.isAudioFile(nodeModel.getName());
if (!ContentHelper.isMediaFile(nodeModel.getRelativeUrl()) && !ContentHelper.isMediaFile(nodeModel.getName())) {
Toast.makeText(getContext(), getString(R.string.InvalidMediaFormat), Toast.LENGTH_LONG).show();
this.getFragmentManager().popBackStack();
return;
} else {
player = ExoPlayer.Factory.newInstance(VIDEO, 1000, 5000);
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
if (nodeModel.getCipherMode().equalsIgnoreCase(CryptoManager.ECB_ENCRYPTION)) {
if (isAudioOnly) {
FileDataSource fileDataSource = new FileDataSource();
Uri uri = NodeHelper.getUriFromNode(nodeModel);
dataSource = new ECBDataSource(fileDataSource, nodeModel.getContentModel().getLicense().getEncryptionKey());
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_SIZE * BUFFER_SEGMENT_COUNT);
audioTrackRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT);
player.prepare(audioTrackRenderer);
} else {
FileDataSource fileDataSource = new FileDataSource();
Uri uri = NodeHelper.getUriFromNode(nodeModel);
dataSource = new ECBDataSource(fileDataSource, nodeModel.getContentModel().getLicense().getEncryptionKey());
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_SIZE * BUFFER_SEGMENT_COUNT);
audioTrackRenderer = new MediaCodecAudioTrackRenderer(sampleSource, MediaCodecSelector.DEFAULT);
videoTrackRenderer = new MediaCodecVideoTrackRenderer(getContext(), sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
ExoPlayer.Factory.newInstance(VIDEO, 1000, 5000);
player.prepare(audioTrackRenderer, videoTrackRenderer);
}
} else {
}
player.seekTo(startPosition);
player.setPlayWhenReady(true);
}
}
ECBDataSource:
public class ECBDataSource implements DataSource {
private static final int LENGTH_UNBOUNDED = -1;
private final DataSource upstream;
private final byte[] encryptionKey;
private CipherInputStream cipherInputStream;
/**
* @param upstream The upstream {@link DataSource}.
* @param encryptionKey The encryption key.
*/
public ECBDataSource(DataSource upstream, byte[] encryptionKey) {
this.upstream = upstream;
this.encryptionKey = encryptionKey;
}
@Override
public long open(DataSpec dataSpec) throws IOException {
Cipher cipher;
try {
cipher = Cipher.getInstance(CryptoManager.ECB_TRANSFORMATION);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(e);
}
Key cipherKey = new SecretKeySpec(encryptionKey, CryptoManager.ENCRYPTION_ALGORITHM);
try {
cipher.init(Cipher.DECRYPT_MODE, cipherKey);
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}
cipherInputStream = new CipherInputStream(new DataSourceInputStream(upstream, dataSpec), cipher);
byte[] contentSize = new byte[4];
cipherInputStream.read(contentSize,0,4);
long four = cipherInputStream.skip(4);
Assertions.checkArgument(four == 4);
return (long)ContentHelper.byteArrayToInt(contentSize);
}
@Override
public void close() throws IOException {
cipherInputStream.close();
cipherInputStream = null;
upstream.close();
}
@Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
Assertions.checkState(cipherInputStream != null);
int bytesRead = cipherInputStream.read(buffer, offset, readLength);//(This is where Exception is thrown)
if (bytesRead < 0) {
return LENGTH_UNBOUNDED;
}
return bytesRead;
}
}
堆栈跟踪:
E/ExoPlayerImplInternal: Internal track renderer error.
com.google.android.exoplayer.ExoPlaybackException: java.io.IOException: Error while finalizing cipher
at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:263)
at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:149)
at com.google.android.exoplayer.ExoPlayerImplInternal.incrementalPrepareInternal(ExoPlayerImplInternal.java:275)
at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:205)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:158)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by: java.io.IOException: Error while finalizing cipher
at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:104)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:155)
at com.Components.ECBDataSource.read(ECBDataSource.java:75)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.readFromDataSource(DefaultExtractorInput.java:240)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.advancePeekPosition(DefaultExtractorInput.java:130)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.peekFully(DefaultExtractorInput.java:110)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.peekFully(DefaultExtractorInput.java:120)
at com.google.android.exoplayer.extractor.webm.Sniffer.sniff(Sniffer.java:59)
at com.google.android.exoplayer.extractor.webm.WebmExtractor.sniff(WebmExtractor.java:288)
at com.google.android.exoplayer.extractor.ExtractorSampleSource$ExtractorHolder.selectExtractor(ExtractorSampleSource.java:888)
at com.google.android.exoplayer.extractor.ExtractorSampleSource$ExtractingLoadable.load(ExtractorSampleSource.java:829)
at com.google.android.exoplayer.upstream.Loader$LoadTask.run(Loader.java:209)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: javax.crypto.IllegalBlockSizeException: error:1e06b07b:Cipher functions:EVP_DecryptFinal_ex:WRONG_FINAL_BLOCK_LENGTH
at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:568)
at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:385)
at javax.crypto.Cipher.doFinal(Cipher.java:1476)
at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:102)
at javax.crypto.CipherInputStream.read(CipherInputStream.java:155)
at com.modevity.core.Components.ECBDataSource.read(ECBDataSource.java:75)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.readFromDataSource(DefaultExtractorInput.java:240)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.advancePeekPosition(DefaultExtractorInput.java:130)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.peekFully(DefaultExtractorInput.java:110)
at com.google.android.exoplayer.extractor.DefaultExtractorInput.peekFully(DefaultExtractorInput.java:120)
at com.google.android.exoplayer.extractor.webm.Sniffer.sniff(Sniffer.java:59)
at com.google.android.exoplayer.extractor.webm.WebmExtractor.sniff(WebmExtractor.java:288)
at com.google.android.exoplayer.extractor.ExtractorSampleSource$ExtractorHolder.selectExtractor(ExtractorSampleSource.java:888)
at com.google.android.exoplayer.extractor.ExtractorSampleSource$ExtractingLoadable.load(ExtractorSampleSource.java:829)
at com.google.android.exoplayer.upstream.Loader$LoadTask.run(Loader.java:209)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
我希望我在某个地方犯了一个愚蠢的错误,你们马上就会发现它们。