diff --git a/proprietary/cryptoPlugin/Android.mk b/proprietary/cryptoPlugin/Android.mk index 7367d19c..96210d35 100644 --- a/proprietary/cryptoPlugin/Android.mk +++ b/proprietary/cryptoPlugin/Android.mk @@ -1,11 +1,17 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +include $(TOP)/vendor/widevine/proprietary/drmwvmplugin/oemcryptolevel.mk -LOCAL_SRC_FILES:= \ - WVCryptoPlugin.cpp +ifeq ($(LOCAL_OEMCRYPTO_LEVEL),1) +LOCAL_CFLAGS := -DREQUIRE_SECURE_BUFFERS +endif + +LOCAL_SRC_FILES := \ + WVCryptoPlugin.cpp LOCAL_C_INCLUDES := \ - $(TOP)/vendor/widevine/proprietary/wvm/include \ + $(TOP)/vendor/widevine/proprietary/wvm/include \ + $(TOP)/external/openssl/include LOCAL_MODULE:= libwvdecryptcommon LOCAL_MODULE_TAGS := optional diff --git a/proprietary/cryptoPlugin/WVCryptoPlugin.cpp b/proprietary/cryptoPlugin/WVCryptoPlugin.cpp index 4c2fc3ee..f52142b3 100644 --- a/proprietary/cryptoPlugin/WVCryptoPlugin.cpp +++ b/proprietary/cryptoPlugin/WVCryptoPlugin.cpp @@ -16,16 +16,20 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "wv_crypto_plugin" +#include #include - -#include "WVCryptoPlugin.h" +#include +#include #include #include +#include +#include "WVCryptoPlugin.h" + +#ifdef REQUIRE_SECURE_BUFFERS #include - -#include +#endif android::CryptoFactory *createCryptoFactory() { return new android::WVCryptoFactory; @@ -40,30 +44,35 @@ const uint8_t WVCryptoFactory::kUUIDWidevine[16] = { }; WVCryptoPlugin::WVCryptoPlugin(const void *data, size_t size) - : mInitCheck(NO_INIT) { - + : mInitCheck(NO_INIT) +{ // not using data at this time, require // size to be zero. if (size > 0) { mInitCheck = -EINVAL; } else { + mInitCheck = OK; + +#ifdef REQUIRE_SECURE_BUFFERS OEMCryptoResult res = OEMCrypto_Initialize(); if (res != OEMCrypto_SUCCESS) { ALOGE("OEMCrypto_Initialize failed: %d", res); mInitCheck = -EINVAL; - } else { - mInitCheck = OK; } +#endif } } WVCryptoPlugin::~WVCryptoPlugin() { + +#ifdef REQUIRE_SECURE_BUFFERS if (mInitCheck == OK) { OEMCryptoResult res = OEMCrypto_Terminate(); if (res != OEMCrypto_SUCCESS) { ALOGW("OEMCrypto_Terminate failed: %d", res); } } +#endif } status_t WVCryptoPlugin::initCheck() const { @@ -71,7 +80,11 @@ status_t WVCryptoPlugin::initCheck() const { } bool WVCryptoPlugin::requiresSecureDecoderComponent(const char *mime) const { +#ifdef REQUIRE_SECURE_BUFFERS return !strncasecmp(mime, "video/", 6); +#else + return false; +#endif } status_t WVCryptoPlugin::decrypt( @@ -85,7 +98,7 @@ status_t WVCryptoPlugin::decrypt( AString *errorDetailMsg) { Mutex::Autolock autoLock(mLock); - //ALOGD("mode=%d, secure=%d, numSubSamples=%d", mode, secure, numSubSamples); + CHECK(mode == kMode_Unencrypted || mode == kMode_AES_WV); size_t offset = 0; @@ -104,6 +117,8 @@ status_t WVCryptoPlugin::decrypt( //ALOGD("size[%d]=%d", i, srcSize); +#ifdef REQUIRE_SECURE_BUFFERS + // decrypt using OEMCrypto API, used for L1 devices OEMCrypto_UINT32 dstLength = srcSize; OEMCryptoResult res; @@ -141,10 +156,88 @@ status_t WVCryptoPlugin::decrypt( } offset += dstLength; +#else + if (mode == kMode_Unencrypted) { + memcpy((char *)dstPtr + offset, (char *)srcPtr + offset, srcSize); + } else { + status_t status = decryptSW(key, (uint8_t *)dstPtr + offset, + (const uint8_t *)srcPtr + offset, srcSize); + if (status != OK) { + ALOGE("decryptSW returned %d", status); + return status; + } + } + + offset += srcSize; +#endif } return OK; } +// SW AES CTS decrypt, used only for L3 devices +status_t WVCryptoPlugin::decryptSW(const uint8_t *key, uint8_t *out, + const uint8_t *in, size_t length) +{ +#ifndef REQUIRE_SECURE_BUFFERS + unsigned char iv[kAES128BlockSize] = {0}; + + if (memcmp(key, mEncKey, sizeof(mEncKey)) != 0) { + // key has changed, recompute mAesKey from key + uint8_t hash[MD5_DIGEST_LENGTH]; + char value[PROPERTY_VALUE_MAX] = {0}; + char seed[] = "34985woeirsdlkfjxc"; + + property_get("ro.serialno", value, NULL); + + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, (uint8_t *)seed, sizeof(seed)); + MD5_Update(&ctx, (uint8_t *)value, strlen(value)); + MD5_Final(hash, &ctx); + + AES_KEY aesKey; + if (AES_set_decrypt_key(hash, sizeof(hash) * 8, &aesKey) == 0) { + uint8_t clearKey[kAES128BlockSize]; + AES_ecb_encrypt(key, clearKey, &aesKey, 0); + + if (AES_set_decrypt_key(clearKey, sizeof(hash) * 8, &mAesKey) == 0) { + memcpy(mEncKey, key, sizeof(mEncKey)); + } else { + return -EINVAL; + } + } else { + return -EINVAL; + } + } + + size_t k, r = length % kAES128BlockSize; + + if (r) { + k = length - r - kAES128BlockSize; + } else { + k = length; + } + + AES_cbc_encrypt(in, out, k, &mAesKey, iv, 0); + + if (r) { + // cipher text stealing - Schneier Figure 9.5 p 196 + unsigned char peniv[kAES128BlockSize] = {0}; + memcpy(peniv, in + k + kAES128BlockSize, r); + + AES_cbc_encrypt(in + k, out + k, kAES128BlockSize, &mAesKey, peniv, 0); + + // exchange the final plaintext and ciphertext + for (size_t i = 0; i < r; i++) { + *(out + k + kAES128BlockSize + i) = *(out + k + i); + *(out + k + i) = *(in + k + kAES128BlockSize + i); + } + AES_cbc_encrypt(out + k, out + k, kAES128BlockSize, &mAesKey, iv, 0); + } +#endif + return OK; +} + } // namespace android diff --git a/proprietary/cryptoPlugin/WVCryptoPlugin.h b/proprietary/cryptoPlugin/WVCryptoPlugin.h index acbf80ee..26752787 100644 --- a/proprietary/cryptoPlugin/WVCryptoPlugin.h +++ b/proprietary/cryptoPlugin/WVCryptoPlugin.h @@ -20,6 +20,7 @@ #include #include +#include namespace android { @@ -27,14 +28,16 @@ struct WVCryptoPlugin : public CryptoPlugin { WVCryptoPlugin(const void *data, size_t size); virtual ~WVCryptoPlugin(); + const static size_t kAES128BlockSize = 16; + status_t initCheck() const; virtual bool requiresSecureDecoderComponent(const char *mime) const; virtual status_t decrypt( bool secure, - const uint8_t key[16], - const uint8_t iv[16], + const uint8_t key[kAES128BlockSize], + const uint8_t iv[kAES128BlockSize], Mode mode, const void *srcPtr, const SubSample *subSamples, size_t numSubSamples, @@ -42,9 +45,13 @@ struct WVCryptoPlugin : public CryptoPlugin { AString *errorDetailMsg); private: + status_t decryptSW(const uint8_t *key, uint8_t *out, const uint8_t *in, size_t length); + Mutex mLock; status_t mInitCheck; + AES_KEY mAesKey; + uint8_t mEncKey[kAES128BlockSize]; WVCryptoPlugin(const WVCryptoPlugin &); WVCryptoPlugin &operator=(const WVCryptoPlugin &); diff --git a/proprietary/cryptoPlugin/decrypt-core.mk b/proprietary/cryptoPlugin/decrypt-core.mk index 23dc2797..d2af6dd5 100644 --- a/proprietary/cryptoPlugin/decrypt-core.mk +++ b/proprietary/cryptoPlugin/decrypt-core.mk @@ -8,10 +8,5 @@ include $(TOP)/vendor/widevine/proprietary/wvm/common.mk LOCAL_WHOLE_STATIC_LIBRARIES := \ libwvdecryptcommon -LOCAL_SHARED_LIBRARIES := \ - libstagefright_foundation \ - libutils \ - LOCAL_STATIC_LIBRARIES := \ - liboemcrypto \ - + liboemcrypto diff --git a/proprietary/drmwvmplugin/include/WVDRMPluginAPI.h b/proprietary/drmwvmplugin/include/WVDRMPluginAPI.h index c4f9371d..6b659c3d 100644 --- a/proprietary/drmwvmplugin/include/WVDRMPluginAPI.h +++ b/proprietary/drmwvmplugin/include/WVDRMPluginAPI.h @@ -71,7 +71,7 @@ class WVDRMPluginAPI { virtual bool RemoveRights(std::string &path) = 0; virtual bool RemoveAllRights() = 0; virtual bool Prepare(char *data, int len) = 0; - virtual int Operate(char *in, char *out, int len, char *iv) = 0; + virtual int Operate(char *in, int inLength, char *out, int outLength, char *iv) = 0; enum EventType { EventType_AcquireDrmInfoFailed, diff --git a/proprietary/drmwvmplugin/lib/arm/libwvdrm_L1.so b/proprietary/drmwvmplugin/lib/arm/libwvdrm_L1.so index 62cbea5a..b2dfefdf 100644 Binary files a/proprietary/drmwvmplugin/lib/arm/libwvdrm_L1.so and b/proprietary/drmwvmplugin/lib/arm/libwvdrm_L1.so differ diff --git a/proprietary/drmwvmplugin/lib/arm/libwvdrm_L3.so b/proprietary/drmwvmplugin/lib/arm/libwvdrm_L3.so index e36b05b4..2d331eed 100644 Binary files a/proprietary/drmwvmplugin/lib/arm/libwvdrm_L3.so and b/proprietary/drmwvmplugin/lib/arm/libwvdrm_L3.so differ diff --git a/proprietary/drmwvmplugin/src/WVMDrmPlugin.cpp b/proprietary/drmwvmplugin/src/WVMDrmPlugin.cpp index 315850d7..fb491c66 100644 --- a/proprietary/drmwvmplugin/src/WVMDrmPlugin.cpp +++ b/proprietary/drmwvmplugin/src/WVMDrmPlugin.cpp @@ -851,10 +851,8 @@ status_t WVMDrmPlugin::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int if (*decBuffer == NULL) return DRM_ERROR_DECRYPT; - (*decBuffer)->length = encBuffer->length; - int status; - status = mDrmPluginImpl->Operate(encBuffer->data, (*decBuffer)->data, encBuffer->length, iv); + status = mDrmPluginImpl->Operate(encBuffer->data, encBuffer->length, (*decBuffer)->data, (*decBuffer)->length, iv); if (status != WVDRMPluginAPI::RIGHTS_VALID) { (*decBuffer)->length = 0; usleep(1000); // prevent spinning diff --git a/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L1.so b/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L1.so index 01cd911d..e74c1b35 100644 Binary files a/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L1.so and b/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L1.so differ diff --git a/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L3.so b/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L3.so index bdf77f76..63801e0c 100644 Binary files a/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L3.so and b/proprietary/streamcontrol/lib/arm/libWVStreamControlAPI_L3.so differ diff --git a/proprietary/wvm/WVMExtractorImpl.cpp b/proprietary/wvm/WVMExtractorImpl.cpp index fe941f59..978d98ae 100644 --- a/proprietary/wvm/WVMExtractorImpl.cpp +++ b/proprietary/wvm/WVMExtractorImpl.cpp @@ -21,7 +21,6 @@ #define AES_BLOCK_SIZE 16 - using namespace android; static sp sDecryptHandle; @@ -33,6 +32,7 @@ static void _cb1(char *data, unsigned long size) if (sDrmManagerClient != NULL) { sDrmManagerClient->initializeDecryptUnit(sDecryptHandle, 0, &buf); } + } static int _cb2(char *in, char *out, int length, char *iv) @@ -141,6 +141,10 @@ void WVMExtractorImpl::Initialize() //ALOGD("WVMExtractorImpl::Initialize setting DecryptCallback\n"); callbacks.decrypt = WVMMediaSource::DecryptCallback; } +#else + if (!mIsLiveStream && mClientContext->getCryptoPluginMode()) { + callbacks.decrypt = WVMMediaSource::DecryptCallback; + } #endif result = WV_Initialize(&callbacks); @@ -351,8 +355,6 @@ status_t WVMExtractorImpl::readMetaData() mClientContext->setVideoSource(mVideoSource); mVideoSource->delegateClientContext(mClientContext); - mFileMetaData->setCString(kKeyMIMEType, "video/wvm"); - mHaveMetaData = true; mInfoListener->configureHeartbeat(); @@ -361,6 +363,26 @@ status_t WVMExtractorImpl::readMetaData() // In crypto plugin mode, need to trigger the drm plugin to begin // license use on playback since the media player isn't involved. sDrmManagerClient->setPlaybackStatus(sDecryptHandle, Playback::START, 0); + +#ifndef REQUIRE_SECURE_BUFFERS + if (!mIsLiveStream) { + // Get the content key for crypto plugin mode on L3 devices + char keyBuffer[AES_BLOCK_SIZE]; + char nullBuffer[0]; + DrmBuffer nullDrmBuffer(nullBuffer, 0); + DrmBuffer keyDrmBuffer(keyBuffer, sizeof(keyBuffer)); + DrmBuffer *keyDrmBufferPtr = &keyDrmBuffer; + + status_t status = sDrmManagerClient->decrypt(sDecryptHandle, 0, &nullDrmBuffer, + &keyDrmBufferPtr, &nullDrmBuffer); + if (status != OK) { + return status; + } + + mVideoSource->SetCryptoPluginKey(keyBuffer); + mAudioSource->SetCryptoPluginKey(keyBuffer); + } +#endif } return OK; @@ -467,11 +489,7 @@ sp WVMExtractorImpl::getTrackMetaData(size_t index, uint32_t flags) } sp WVMExtractorImpl::getMetaData() { - status_t err; - if ((err = readMetaData()) != OK) { - return new MetaData; - } - + mFileMetaData->setCString(kKeyMIMEType, "video/wvm"); return mFileMetaData; } diff --git a/proprietary/wvm/WVMMediaSource.cpp b/proprietary/wvm/WVMMediaSource.cpp index 7d86fe66..255188f1 100644 --- a/proprietary/wvm/WVMMediaSource.cpp +++ b/proprietary/wvm/WVMMediaSource.cpp @@ -36,6 +36,7 @@ WVMMediaSource::WVMMediaSource(WVSession *session, WVEsSelector esSelector, mNewSegment(false), mCryptoInitialized(false), mIsStalled(false), + mStripADTS(false), mGroup(NULL), mKeyTime(0), mDts(0), @@ -53,6 +54,11 @@ WVMMediaSource::WVMMediaSource(WVSession *session, WVEsSelector esSelector, } } } + mStripADTS = true; +#else + if (cryptoPluginMode) { + mStripADTS = true; + } #endif } @@ -171,19 +177,21 @@ sp WVMMediaSource::getFormat() { Mutex::Autolock autoLock(mLock); -#ifdef REQUIRE_SECURE_BUFFERS if (!mIsLiveStream) { +#ifdef REQUIRE_SECURE_BUFFERS if (mESSelector == WV_EsSelector_Video) { mTrackMetaData->setInt32(kKeyRequiresSecureBuffers, true); } +#endif - // Only support AAC on android for now, so assume the audio - // track is AAC and notify the audio codec it has ADTS framing - if (mESSelector == WV_EsSelector_Audio) { - mTrackMetaData->setInt32(kKeyIsADTS, 1); + if (mStripADTS) { + // Only support AAC on android for now, so assume the audio + // track is AAC and notify the audio codec it has ADTS framing + if (mESSelector == WV_EsSelector_Audio) { + mTrackMetaData->setInt32(kKeyIsADTS, 1); + } } } -#endif return mTrackMetaData; } @@ -260,10 +268,8 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) return err; } -#ifdef REQUIRE_SECURE_BUFFERS mDecryptContext.Initialize(mediaBuf); mEncryptedSizes.clear(); -#endif size_t bytesRead; bool auStart; @@ -351,10 +357,8 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) // drop frames up to next sync if requested mIsStalled = true; usleep(10000); -#ifdef REQUIRE_SECURE_BUFFERS mDecryptContext.Initialize(mediaBuf); mEncryptedSizes.clear(); -#endif continue; } @@ -394,13 +398,15 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) mediaBuf->set_range(0, bytesRead + offset); -#ifdef REQUIRE_SECURE_BUFFERS if (!mIsLiveStream && mEncryptedSizes.size()) { mediaBuf->meta_data()->setData(kKeyEncryptedSizes, 0, &mEncryptedSizes[0], mEncryptedSizes.size() * sizeof(size_t)); mediaBuf->meta_data()->setInt32(kKeyCryptoMode, CryptoPlugin::kMode_AES_WV); - } + +#ifndef REQUIRE_SECURE_BUFFERS + mediaBuf->meta_data()->setData(kKeyCryptoKey, 0, mCryptoPluginKey, sizeof(mCryptoPluginKey)); #endif + } #if 0 // debug code - log packets to files @@ -432,7 +438,6 @@ status_t WVMMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) return OK; } -#ifdef REQUIRE_SECURE_BUFFERS void WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* output, size_t length, int key, void *obj) @@ -453,10 +458,7 @@ void WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* out source = clientContext->getAudioSource(); DecryptContext &context = source->getDecryptContext(); - - OEMCrypto_UINT32 copied = length; - OEMCryptoResult result; - unsigned char *iv = NULL; + uint32_t copied = length; if (clientContext->getCryptoPluginMode()) { // just determine crypto unit boundaries @@ -465,7 +467,12 @@ void WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* out } memcpy((uint8_t *)context.mMediaBuf->data() + context.mOffset, input, length); } else { + +#ifdef REQUIRE_SECURE_BUFFERS // do decrypt + OEMCryptoResult result; + unsigned char *iv = NULL; + if (key) iv = context.mIV; @@ -482,10 +489,10 @@ void WVMMediaSource::DecryptCallback(WVEsSelector esType, void* input, void* out if (result != OEMCrypto_SUCCESS) { ALOGD("OEMCrypto decrypt failure: %d", result); } +#endif } context.mOffset += copied; } -#endif WVMMediaSource::~WVMMediaSource() diff --git a/proprietary/wvm/include/WVMMediaSource.h b/proprietary/wvm/include/WVMMediaSource.h index b16ce57a..78c13009 100644 --- a/proprietary/wvm/include/WVMMediaSource.h +++ b/proprietary/wvm/include/WVMMediaSource.h @@ -47,7 +47,8 @@ public: int64_t getTime() { return mKeyTime; }; // usec. -#ifdef REQUIRE_SECURE_BUFFERS + static const int kCryptoBlockSize = 16; + class DecryptContext { public: void Initialize(MediaBuffer *mediaBuf) { @@ -57,16 +58,19 @@ public: } MediaBuffer *mMediaBuf; size_t mOffset; - static const int kCryptoBlockSize = 16; unsigned char mIV[kCryptoBlockSize]; }; static void DecryptCallback(WVEsSelector esType, void* input, void* output, size_t length, int key, void *context); DecryptContext& getDecryptContext() { return mDecryptContext; } + + void SetCryptoPluginKey(const char key[kCryptoBlockSize]) { + memcpy(mCryptoPluginKey, key, sizeof(mCryptoPluginKey)); + } + private: DecryptContext mDecryptContext; -#endif protected: virtual ~WVMMediaSource(); @@ -85,6 +89,7 @@ private: bool mNewSegment; bool mCryptoInitialized; bool mIsStalled; + bool mStripADTS; MediaBufferGroup *mGroup; @@ -97,6 +102,7 @@ private: sp mClientContext; Vector mEncryptedSizes; + char mCryptoPluginKey[kCryptoBlockSize]; void allocBufferGroup();