使用exoplayer进行Ecb加密

时间:2016-06-06 13:11:12

标签: android encryption exoplayer

我需要支持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) 

我希望我在某个地方犯了一个愚蠢的错误,你们马上就会发现它们。

0 个答案:

没有答案