diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 6568b85a..07732020 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -138,12 +138,14 @@ CdmResponseType CdmSession::Decrypt(bool is_encrypted, return UNKNOWN_ERROR; // Check if key needs to be selected - if (key_id_.compare(key_id) != 0) { - if (crypto_session_->SelectKey(key_id)) { - key_id_ = key_id; - } - else { - return UNKNOWN_ERROR; + if (is_encrypted) { + if (key_id_.compare(key_id) != 0) { + if (crypto_session_->SelectKey(key_id)) { + key_id_ = key_id; + } + else { + return UNKNOWN_ERROR; + } } } diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp index 82d48055..1067b077 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp @@ -856,6 +856,12 @@ bool CryptoEngine::DecryptCTR(SessionContext* session, void* clear_data, BufferType buffer_type) { + if (! is_encrypted) { + memcpy(reinterpret_cast(clear_data), + &cipher_data[0], cipher_data.size()); + return true; + } + // Check there is a content key if (session->current_content_key() == NULL) { LOGE("[DecryptCTR(): OEMCrypto_ERROR_NO_CONTENT_KEY]"); @@ -902,12 +908,6 @@ bool CryptoEngine::DecryptCTR(SessionContext* session, return true; } - if (! is_encrypted) { - memcpy(reinterpret_cast(clear_data), - &cipher_data[0], cipher_data.size()); - return true; - } - // Local copy (will be modified). uint8_t aes_iv[AES_BLOCK_SIZE]; if (static_cast(iv.size()) != AES_BLOCK_SIZE) { diff --git a/libwvdrmengine/test/java/Android.mk b/libwvdrmengine/test/java/Android.mk index ac7dddf4..b8d5e7fe 100644 --- a/libwvdrmengine/test/java/Android.mk +++ b/libwvdrmengine/test/java/Android.mk @@ -7,7 +7,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MediaDrmAPITest -LOCAL_SDK_VERSION := current +# TODO: Uncomment this line when the MediaDrm APIs are unhidden +#LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java b/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java index f5ae0825..43eca1d9 100644 --- a/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java +++ b/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java @@ -154,6 +154,11 @@ public class MediaDrmAPITest extends TabActivity { listDecoders(); + testClearContentNoKeys(); + testEncryptedContent(); + } + + private void testEncryptedContent() { try { MediaDrm drm = new MediaDrm(kWidevineScheme); byte[] sessionId = drm.openSession(); @@ -167,6 +172,19 @@ public class MediaDrmAPITest extends TabActivity { } } + private void testClearContentNoKeys() { + try { + MediaDrm drm = new MediaDrm(kWidevineScheme); + byte[] sessionId = drm.openSession(); + + testClear(sessionId); + + drm.closeSession(sessionId); + } catch (Exception e) { + e.printStackTrace(); + } + } + public void doLicenseExchange(MediaDrm drm, byte[] sessionId) throws Exception { MediaDrm.KeyRequest drmRequest; drmRequest = drm.getKeyRequest(sessionId, kKeyId, "video/avc", @@ -207,6 +225,7 @@ public class MediaDrmAPITest extends TabActivity { // do minimal codec setup to pass an encrypted buffer down the stack to see if it gets // decrypted correctly. public void testDecrypt(byte[] sessionId) throws Exception { + Log.i(TAG, "testDecrypt"); MediaCrypto crypto; try { @@ -287,7 +306,80 @@ public class MediaDrmAPITest extends TabActivity { codec.stop(); codec.release(); - Log.i(TAG, "all done!"); + Log.i(TAG, "testDecrypt: all done!"); + } + + // do minimal codec setup to pass a clear buffer down the stack to see if it gets + // passed through correctly. + public void testClear(byte[] sessionId) throws Exception { + Log.i(TAG, "testClear"); + + MediaCrypto crypto; + try { + crypto = new MediaCrypto(kWidevineScheme, getTestModeSessionId(sessionId)); + } catch (MediaCryptoException e) { + throw e; + } + + String mime = "video/avc"; + MediaCodec codec; + if (crypto.requiresSecureDecoderComponent(mime)) { + codec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime)); + } else { + codec = MediaCodec.createDecoderByType(mime); + } + + MediaFormat format = MediaFormat.createVideoFormat(mime, 640, 480); + codec.configure(format, null, crypto, 0); + + codec.start(); + + ByteBuffer[] inputBuffers = codec.getInputBuffers(); + ByteBuffer[] outputBuffers = codec.getOutputBuffers(); + + + int index; + Log.i(TAG, "waiting for buffer..."); + while ((index = codec.dequeueInputBuffer(0 /* timeoutUs */)) < 0) { + Thread.sleep(10); + } + Log.i(TAG, "Got index " + index); + + LinkedList vectors = TestVectors.GetTestVectors(); + ListIterator iter = vectors.listIterator(0); + while (iter.hasNext()) { + TestVector tv = iter.next(); + + inputBuffers[index].clear(); + inputBuffers[index].put(tv.mClearBuf, 0, tv.mClearBuf.length); + + try { + codec.queueInputBuffer(index, 0 /* offset */, tv.mClearBuf.length, + 0 /* sampleTime */, 0 /* flags */); + } catch (CryptoException e) { + ByteBuffer refBuffer = ByteBuffer.allocate(tv.mClearBuf.length); + refBuffer.put(tv.mClearBuf, 0, tv.mClearBuf.length); + + // in test mode, the WV CryptoPlugin throws a CryptoException where the + // message string contains a SHA256 hash of the decrypted data, for verification + // purposes. + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] sha256 = digest.digest(refBuffer.array()); + if (Arrays.equals(sha256, hex2ba(e.getMessage()))) { + Log.i(TAG, "sha256: " + e.getMessage() + " matches OK"); + } else { + Log.i(TAG, "MediaCrypto sha256: " + e.getMessage() + + "does not match test vector sha256: "); + for (int i = 0; i < sha256.length; i++) { + System.out.printf("%02x", sha256[i]); + } + } + } + } + + codec.stop(); + codec.release(); + Log.i(TAG, "testClear: all done!"); } private String getSecureDecoderNameForMime(String mime) {