// // Copyright 2013 Google Inc. All Rights Reserved. // #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "media/stagefright/foundation/ABase.h" #include "media/stagefright/foundation/AString.h" #include "wv_cdm_constants.h" #include "wv_cdm_types.h" #include "wv_content_decryption_module.h" #include "WVCryptoPlugin.h" using namespace android; using namespace std; using namespace testing; using namespace wvcdm; using namespace wvdrm; class MockCDM : public WvContentDecryptionModule { public: MOCK_METHOD9(Decrypt, CdmResponseType(const CdmSessionId&, bool, const KeyId&, const uint8_t*, size_t, const std::vector&, size_t, void*, size_t)); MOCK_METHOD1(QueryStatus, CdmResponseType(CdmQueryMap*)); }; class WVCryptoPluginTest : public Test { protected: static const uint32_t kSessionIdSize = 16; uint8_t sessionId[kSessionIdSize]; uint8_t keyId[KEY_ID_SIZE]; uint8_t iv[KEY_IV_SIZE]; static const uint32_t kDataSize = 64; uint8_t in[kDataSize]; uint8_t out[kDataSize]; static const uint32_t kSubSampleCount = 3; CryptoPlugin::SubSample subSamples[kSubSampleCount]; virtual void SetUp() { FILE* fp = fopen("/dev/urandom", "r"); fread(sessionId, sizeof(uint8_t), kSessionIdSize, fp); fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); fread(in, sizeof(uint8_t), kDataSize, fp); fclose(fp); memset(out, 0, sizeof(out)); memset(subSamples, 0, sizeof(subSamples)); subSamples[0].mNumBytesOfEncryptedData = 16; subSamples[1].mNumBytesOfClearData = 16; subSamples[1].mNumBytesOfEncryptedData = 24; subSamples[2].mNumBytesOfEncryptedData = 8; // Set default CdmResponseType value for gMock DefaultValue::Set(wvcdm::NO_ERROR); } }; TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) { MockCDM cdm; WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm); CdmQueryMap l1Map; l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; CdmQueryMap l3Map; l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; EXPECT_CALL(cdm, QueryStatus(_)) .WillOnce(DoAll(SetArgPointee<0>(l1Map), Return(wvcdm::NO_ERROR))) .WillOnce(DoAll(SetArgPointee<0>(l3Map), Return(wvcdm::NO_ERROR))); EXPECT_TRUE(plugin.requiresSecureDecoderComponent("video/mp4")) << "WVCryptoPlugin incorrectly allows an insecure video decoder on L1"; EXPECT_FALSE(plugin.requiresSecureDecoderComponent("video/mp4")) << "WVCryptoPlugin incorrectly expects a secure video decoder on L3"; EXPECT_FALSE(plugin.requiresSecureDecoderComponent("audio/aac")) << "WVCryptoPlugin incorrectly expects a secure audio decoder"; } TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) { MockCDM cdm; WVCryptoPlugin plugin(sessionId, kSessionIdSize, &cdm); // Specify the expected calls to Decrypt { InSequence calls; EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true, ElementsAreArray(keyId, KEY_ID_SIZE), in, 16, ElementsAreArray(iv, KEY_IV_SIZE), 0, out, 0)) .WillOnce(Return(wvcdm::NO_ERROR)); EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false, ElementsAreArray(keyId, KEY_ID_SIZE), in + 16, 16, ElementsAreArray(iv, KEY_IV_SIZE), 0, out, 16)) .WillOnce(Return(wvcdm::NO_ERROR)); EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true, ElementsAreArray(keyId, KEY_ID_SIZE), in + 32, 24, ElementsAreArray(iv, KEY_IV_SIZE), 0, out, 32)) .WillOnce(Return(wvcdm::NO_ERROR)); EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true, ElementsAreArray(keyId, KEY_ID_SIZE), in + 56, 8, ElementsAreArray(iv, KEY_IV_SIZE), 8, out, 56)) .WillOnce(Return(wvcdm::NO_ERROR)); } AString errorDetailMessage; ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, in, subSamples, kSubSampleCount, out, &errorDetailMessage); EXPECT_EQ(static_cast(kDataSize), res) << "WVCryptoPlugin decrypted the wrong number of bytes"; EXPECT_EQ(0u, errorDetailMessage.size()) << "WVCryptoPlugin reported a detailed error message."; }