From ff7f8c00bfdabdd162a4d25aaa14b5aef5df6a12 Mon Sep 17 00:00:00 2001 From: "John W. Bruce" Date: Wed, 16 Jan 2019 16:34:52 -0800 Subject: [PATCH] Fix IV handling for pattern encryption. (This is a merge of modmaker@'s change from the Widevine repo, http://go/wvgerrit/48880) When using pattern encryption, WVCryptoPlugin needs to increment the IV after each subsample. It should increment it based on the number of actually encrypted samples (i.e. ignore clear data caused by subsamples or pattern encryption). In the common encryption spec, section 9.6.1 states: If the last Block pattern in a Subsample is incomplete, the partial pattern SHALL be followed until truncated by the BytesOfProtectedData size and any partial crypt_byte_block SHALL remain unencrypted. This fixes the counting of encrypted blocks to account for partial patterns. This also makes it more efficient by removing the loop. Bug: 111001481 Test: build_and_run_all_unit_tests Test: Widevine GTS Tests Change-Id: Ibd2bf10f64461b9bce10ef07453096fe4a4f6376 --- .../mediacrypto/include/WVCryptoPlugin.h | 2 - .../mediacrypto/include_hidl/WVCryptoPlugin.h | 2 - .../mediacrypto/src/WVCryptoPlugin.cpp | 36 +++++------------- .../mediacrypto/src_hidl/WVCryptoPlugin.cpp | 38 +++++-------------- 4 files changed, 20 insertions(+), 58 deletions(-) diff --git a/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h b/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h index 9d51a225..ee035864 100644 --- a/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h +++ b/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h @@ -50,8 +50,6 @@ class WVCryptoPlugin : public android::CryptoPlugin { android::status_t attemptDecrypt( const wvcdm::CdmDecryptionParameters& params, bool haveEncryptedSubsamples, android::AString* errorDetailMsg); - static wvcdm::CdmResponseType countEncryptedBlocksInPatternedRange( - size_t range, const Pattern& pattern, uint64_t* result); static void incrementIV(uint64_t increaseBy, std::vector* ivPtr); }; diff --git a/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h b/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h index c020bc7e..a7570731 100644 --- a/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h +++ b/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h @@ -72,8 +72,6 @@ struct WVCryptoPlugin : public ICryptoPlugin { Status_V1_2 attemptDecrypt( const wvcdm::CdmDecryptionParameters& params, bool haveEncryptedSubsamples, std::string* errorDetailMsg); - static wvcdm::CdmResponseType countEncryptedBlocksInPatternedRange( - size_t range, const Pattern& pattern, uint64_t* result); static void incrementIV(uint64_t increaseBy, std::vector* ivPtr); }; diff --git a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp index ee72cc32..ec9005b6 100644 --- a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp +++ b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp @@ -234,12 +234,16 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE], increment = (blockOffset + subSample.mNumBytesOfEncryptedData) / kAESBlockSize; } else { - CdmResponseType countRes = countEncryptedBlocksInPatternedRange( - subSample.mNumBytesOfEncryptedData, pattern, &increment); - if (!isCdmResponseTypeSuccess(countRes)) { - // Swallow the specifics of the error to obscure decrypt internals. - return kErrorCDMGeneric; - } + const uint64_t numBlocks = + subSample.mNumBytesOfEncryptedData / kAESBlockSize; + const uint64_t patternLengthInBlocks = + pattern.mEncryptBlocks + pattern.mSkipBlocks; + increment = + (numBlocks / patternLengthInBlocks) * pattern.mEncryptBlocks; + // A partial pattern is only encrypted if it is at least + // mEncryptBlocks large. + if (numBlocks % patternLengthInBlocks >= pattern.mEncryptBlocks) + increment += pattern.mEncryptBlocks; } incrementIV(increment, &ivVector); @@ -348,26 +352,6 @@ status_t WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params, } } -CdmResponseType WVCryptoPlugin::countEncryptedBlocksInPatternedRange( - size_t range, const Pattern& pattern, uint64_t* result) { - if (result == NULL || range % kAESBlockSize != 0) { - return wvcdm::UNKNOWN_ERROR; - } - - const size_t patternLength = pattern.mEncryptBlocks + pattern.mSkipBlocks; - uint64_t encryptedBlocksPassed = 0; - size_t patternPosition = 0; - for (size_t remaining = range / kAESBlockSize; remaining > 0; --remaining) { - if (patternPosition < pattern.mEncryptBlocks) { - ++encryptedBlocksPassed; - } - patternPosition = (patternPosition + 1) % patternLength; - } - - *result = encryptedBlocksPassed; - return wvcdm::NO_ERROR; -} - void WVCryptoPlugin::incrementIV(uint64_t increaseBy, vector* ivPtr) { vector& iv = *ivPtr; uint64_t* counterBuffer = reinterpret_cast(&iv[8]); diff --git a/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp index 8ccb3da5..36aa7ce3 100644 --- a/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp +++ b/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp @@ -338,14 +338,16 @@ Return WVCryptoPlugin::decrypt_1_2( increment = (blockOffset + subSample.numBytesOfEncryptedData) / kAESBlockSize; } else { - CdmResponseType countRes = countEncryptedBlocksInPatternedRange( - subSample.numBytesOfEncryptedData, pattern, &increment); - if (!isCdmResponseTypeSuccess(countRes)) { - // Swallow the specifics of the error to obscure decrypt internals. - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, - "Error decrypting data: unknown error"); - return Void(); - } + const uint64_t numBlocks = + subSample.numBytesOfEncryptedData / kAESBlockSize; + const uint64_t patternLengthInBlocks = + pattern.encryptBlocks + pattern.skipBlocks; + increment = + (numBlocks / patternLengthInBlocks) * pattern.encryptBlocks; + // A partial pattern is only encrypted if it is at least + // mEncryptBlocks large. + if (numBlocks % patternLengthInBlocks >= pattern.encryptBlocks) + increment += pattern.encryptBlocks; } incrementIV(increment, &ivVector); @@ -429,26 +431,6 @@ Status_V1_2 WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params } } -CdmResponseType WVCryptoPlugin::countEncryptedBlocksInPatternedRange( - size_t range, const Pattern& pattern, uint64_t* result) { - if (result == NULL || range % kAESBlockSize != 0) { - return wvcdm::UNKNOWN_ERROR; - } - - const size_t patternLength = pattern.encryptBlocks + pattern.skipBlocks; - uint64_t encryptedBlocksPassed = 0; - size_t patternPosition = 0; - for (size_t remaining = range / kAESBlockSize; remaining > 0; --remaining) { - if (patternPosition < pattern.encryptBlocks) { - ++encryptedBlocksPassed; - } - patternPosition = (patternPosition + 1) % patternLength; - } - - *result = encryptedBlocksPassed; - return wvcdm::NO_ERROR; -} - void WVCryptoPlugin::incrementIV(uint64_t increaseBy, std::vector* ivPtr) { std::vector& iv = *ivPtr;