175 lines
6.2 KiB
C++
175 lines
6.2 KiB
C++
//
|
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#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<uint8_t>&, 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];
|
|
|
|
virtual void SetUp() {
|
|
FILE* fp = fopen("/dev/urandom", "r");
|
|
fread(sessionId, sizeof(uint8_t), kSessionIdSize, fp);
|
|
fclose(fp);
|
|
|
|
// Set default CdmResponseType value for gMock
|
|
DefaultValue<CdmResponseType>::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);
|
|
|
|
uint8_t keyId[KEY_ID_SIZE];
|
|
uint8_t baseIv[KEY_IV_SIZE];
|
|
|
|
static const size_t kDataSize = 185;
|
|
uint8_t in[kDataSize];
|
|
uint8_t out[kDataSize];
|
|
|
|
FILE* fp = fopen("/dev/urandom", "r");
|
|
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
|
fread(baseIv, sizeof(uint8_t), KEY_IV_SIZE, fp);
|
|
fread(in, sizeof(uint8_t), kDataSize, fp);
|
|
fclose(fp);
|
|
|
|
static const size_t kSubSampleCount = 6;
|
|
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
|
memset(subSamples, 0, sizeof(subSamples));
|
|
subSamples[0].mNumBytesOfEncryptedData = 16; // 0
|
|
subSamples[1].mNumBytesOfClearData = 16; // 1
|
|
subSamples[1].mNumBytesOfEncryptedData = 16; // 1
|
|
subSamples[2].mNumBytesOfEncryptedData = 8; // 2
|
|
subSamples[3].mNumBytesOfClearData = 29; // 2
|
|
subSamples[3].mNumBytesOfEncryptedData = 24; // 2
|
|
subSamples[4].mNumBytesOfEncryptedData = 60; // 3
|
|
subSamples[5].mNumBytesOfEncryptedData = 16; // 4
|
|
|
|
uint8_t iv[5][KEY_IV_SIZE];
|
|
memcpy(iv[0], baseIv, sizeof(baseIv));
|
|
iv[0][15] = 0;
|
|
memcpy(iv[1], baseIv, sizeof(baseIv));
|
|
iv[1][15] = 1;
|
|
memcpy(iv[2], baseIv, sizeof(baseIv));
|
|
iv[2][15] = 2;
|
|
memcpy(iv[3], baseIv, sizeof(baseIv));
|
|
iv[3][15] = 4;
|
|
memcpy(iv[4], baseIv, sizeof(baseIv));
|
|
iv[4][15] = 7;
|
|
|
|
{
|
|
InSequence calls;
|
|
|
|
// SubSample 0
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in, 16,
|
|
ElementsAreArray(iv[0], KEY_IV_SIZE), 0, out, 0))
|
|
.Times(1);
|
|
|
|
// SubSample 1
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 16, 16,
|
|
ElementsAreArray(iv[1], KEY_IV_SIZE), 0, out, 16))
|
|
.Times(1);
|
|
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 32, 16,
|
|
ElementsAreArray(iv[1], KEY_IV_SIZE), 0, out, 32))
|
|
.Times(1);
|
|
|
|
// SubSample 2
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 48, 8,
|
|
ElementsAreArray(iv[2], KEY_IV_SIZE), 0, out, 48))
|
|
.Times(1);
|
|
|
|
// SubSample 3
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), false,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 56, 29,
|
|
ElementsAreArray(iv[2], KEY_IV_SIZE), 0, out, 56))
|
|
.Times(1);
|
|
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 85, 24,
|
|
ElementsAreArray(iv[2], KEY_IV_SIZE), 8, out, 85))
|
|
.Times(1);
|
|
|
|
// SubSample 4
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 109, 60,
|
|
ElementsAreArray(iv[3], KEY_IV_SIZE), 0, out, 109))
|
|
.Times(1);
|
|
|
|
// SubSample 5
|
|
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize), true,
|
|
ElementsAreArray(keyId, KEY_ID_SIZE), in + 169, 16,
|
|
ElementsAreArray(iv[4], KEY_IV_SIZE), 12, out, 169))
|
|
.Times(1);
|
|
}
|
|
|
|
AString errorDetailMessage;
|
|
|
|
ssize_t res = plugin.decrypt(false, keyId, iv[0], CryptoPlugin::kMode_AES_CTR,
|
|
in, subSamples, kSubSampleCount, out,
|
|
&errorDetailMessage);
|
|
|
|
EXPECT_EQ(static_cast<ssize_t>(kDataSize), res) <<
|
|
"WVCryptoPlugin decrypted the wrong number of bytes";
|
|
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
|
"WVCryptoPlugin reported a detailed error message.";
|
|
}
|