Specify generic encryption buffer sizes

Merge from widevine repo of http://go/wvgerrit/17463

This CL updates the unit tests to verify that
OEMCrypto_Generic_Encrypt and OEMCrypto_Generic_Decrypt can handle a
buffer size of at least 100k.  It also adds code to the
oemcrypto_dynamic_adapter so that buffer sizes that are larger than
100k are broken into chunks of 100k.

All Nexus devices targeted for N pass these tests.

b/27040752

Change-Id: Iaf5c65d2f0b69e60f03cc99732d1ecab60658049
This commit is contained in:
Fred Gylys-Colwell
2016-04-08 13:44:44 -07:00
parent 91059f1d81
commit 2717f29707
4 changed files with 138 additions and 17 deletions

View File

@@ -24,6 +24,7 @@
#include "log.h"
#include "profiled_scope.h"
#include "properties.h"
#include "wv_cdm_constants.h"
using namespace wvoec3;
using wvcdm::kLevelDefault;
@@ -31,6 +32,8 @@ using wvcdm::kLevel3;
namespace {
static const size_t kMaxGenericEncryptChunkSize = 100*1024;
typedef struct {
const uint8_t* key_id;
size_t key_id_length;
@@ -1107,8 +1110,23 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt(
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return pair.fcn->Generic_Encrypt(pair.session, in_buffer, buffer_length, iv,
algorithm, out_buffer);
OEMCryptoResult status = OEMCrypto_SUCCESS;
std::vector<uint8_t> current_iv(iv, iv + wvcdm::KEY_IV_SIZE);
while (buffer_length > 0 && status == OEMCrypto_SUCCESS) {
const size_t chunk_size = std::min(buffer_length,
kMaxGenericEncryptChunkSize);
status = pair.fcn->Generic_Encrypt(pair.session, in_buffer, chunk_size,
&current_iv[0],
algorithm, out_buffer);
buffer_length -= chunk_size;
in_buffer += chunk_size;
out_buffer += chunk_size;
if (buffer_length > 0) {
current_iv.assign(out_buffer - wvcdm::KEY_IV_SIZE,
out_buffer);
}
}
return status;
}
extern "C" OEMCryptoResult OEMCrypto_Generic_Decrypt(
@@ -1121,8 +1139,23 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Decrypt(
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return pair.fcn->Generic_Decrypt(pair.session, in_buffer, buffer_length, iv,
algorithm, out_buffer);
OEMCryptoResult status = OEMCrypto_SUCCESS;
std::vector<uint8_t> current_iv(iv, iv + wvcdm::KEY_IV_SIZE);
while (buffer_length > 0 && status == OEMCrypto_SUCCESS) {
const size_t chunk_size = std::min(buffer_length,
kMaxGenericEncryptChunkSize);
status = pair.fcn->Generic_Decrypt(pair.session, in_buffer, chunk_size,
&current_iv[0],
algorithm, out_buffer);
buffer_length -= chunk_size;
in_buffer += chunk_size;
out_buffer += chunk_size;
if (buffer_length > 0) {
current_iv.assign(in_buffer - wvcdm::KEY_IV_SIZE,
in_buffer);
}
}
return status;
}
extern "C" OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,

View File

@@ -2464,7 +2464,7 @@ class OEMCryptoSessionTestsDecryptTests
pattern_.offset; // block index into encrypted/skip block pattern.
size_t buffer_index = 0; // byte index into in and out.
size_t block_offset = 0; // byte index into current block.
for (int i = 0; i < subsample_size_.size(); i++) {
for (size_t i = 0; i < subsample_size_.size(); i++) {
// Copy clear content.
if (subsample_size_[i].clear_size > 0) {
memcpy(&(*out_buffer)[buffer_index], &in_buffer[buffer_index],
@@ -4431,7 +4431,7 @@ class GenericCryptoTest : public OEMCryptoSessionTests {
session_.license().keys[2].key_data_length = wvcdm::MAC_KEY_SIZE;
session_.license().keys[3].key_data_length = wvcdm::MAC_KEY_SIZE;
clear_buffer_.assign(kBufferSize, 0);
clear_buffer_.assign(buffer_size_, 0);
for (size_t i = 0; i < clear_buffer_.size(); i++) {
clear_buffer_[i] = 1 + i % 250;
}
@@ -4542,7 +4542,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests {
EXPECT_NE(OEMCrypto_SUCCESS, sts);
}
static const size_t kBufferSize = 160; // multiple of encryption block size.
// This must be a multiple of encryption block size.
size_t buffer_size_ = 160;
vector<uint8_t> clear_buffer_;
vector<uint8_t> encrypted_buffer_;
uint8_t iv_[wvcdm::KEY_IV_SIZE];
@@ -4571,11 +4572,12 @@ TEST_F(GenericCryptoTest, GenericKeyEncrypt) {
TEST_F(GenericCryptoTest, GenericKeyBadEncrypt) {
EncryptAndLoadKeys();
BadEncrypt(0, OEMCrypto_HMAC_SHA256, kBufferSize);
BadEncrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize - 10);
BadEncrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize);
BadEncrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize);
BadEncrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize);
BadEncrypt(0, OEMCrypto_HMAC_SHA256, buffer_size_);
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
BadEncrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
BadEncrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadEncrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadEncrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
}
TEST_F(GenericCryptoTest, GenericKeyDecrypt) {
@@ -4618,11 +4620,12 @@ TEST_F(GenericCryptoTest, GenericSecureToClear) {
TEST_F(GenericCryptoTest, GenericKeyBadDecrypt) {
EncryptAndLoadKeys();
BadDecrypt(1, OEMCrypto_HMAC_SHA256, kBufferSize);
BadDecrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize - 10);
BadDecrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize);
BadDecrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize);
BadDecrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, kBufferSize);
BadDecrypt(1, OEMCrypto_HMAC_SHA256, buffer_size_);
// The buffer size must be a multiple of 16, so subtracting 10 is bad.
BadDecrypt(1, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_ - 10);
BadDecrypt(0, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadDecrypt(2, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
BadDecrypt(3, OEMCrypto_AES_CBC_128_NO_PADDING, buffer_size_);
}
TEST_F(GenericCryptoTest, GenericKeySign) {
@@ -4686,6 +4689,91 @@ TEST_F(GenericCryptoTest, GenericKeyBadVerify) {
BadVerify(3, OEMCrypto_AES_CBC_128_NO_PADDING, SHA256_DIGEST_LENGTH, false);
}
TEST_F(GenericCryptoTest, GenericKeyEncryptLargeBufferAPI11) {
// Some applications are known to pass in a block that is almost 400k, but
// the layer above oemcrypto can break it into 100k chunks.
buffer_size_ = 100 * 1024;
EncryptAndLoadKeys();
unsigned int key_index = 0;
vector<uint8_t> expected_encrypted;
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_SelectKey(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length));
vector<uint8_t> encrypted(clear_buffer_.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_Generic_Encrypt(
session_.session_id(), &clear_buffer_[0], clear_buffer_.size(),
iv_, OEMCrypto_AES_CBC_128_NO_PADDING, &encrypted[0]));
ASSERT_EQ(expected_encrypted, encrypted);
}
TEST_F(GenericCryptoTest, GenericKeyDecryptLargeBufferAPI11) {
// Some applications are known to pass in a block that is almost 400k.
buffer_size_ = 400 * 1024;
EncryptAndLoadKeys();
unsigned int key_index = 1;
vector<uint8_t> encrypted;
EncryptBuffer(key_index, clear_buffer_, &encrypted);
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_SelectKey(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length));
vector<uint8_t> resultant(encrypted.size());
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_Generic_Decrypt(
session_.session_id(), &encrypted[0], encrypted.size(), iv_,
OEMCrypto_AES_CBC_128_NO_PADDING, &resultant[0]));
ASSERT_EQ(clear_buffer_, resultant);
}
TEST_F(GenericCryptoTest, GenericKeySignLargeBufferAPI11) {
buffer_size_ = 100 * 1024;
EncryptAndLoadKeys();
unsigned int key_index = 2;
vector<uint8_t> expected_signature;
SignBuffer(key_index, clear_buffer_, &expected_signature);
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_SelectKey(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length));
size_t gen_signature_length = 0;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_Generic_Sign(session_.session_id(), &clear_buffer_[0],
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
NULL, &gen_signature_length));
ASSERT_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), gen_signature_length);
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_Generic_Sign(session_.session_id(), &clear_buffer_[0],
clear_buffer_.size(), OEMCrypto_HMAC_SHA256,
&signature[0], &gen_signature_length));
ASSERT_EQ(expected_signature, signature);
}
TEST_F(GenericCryptoTest, GenericKeyVerifyLargeBufferAPI11) {
buffer_size_ = 100 * 1024;
EncryptAndLoadKeys();
unsigned int key_index = 3;
vector<uint8_t> signature;
SignBuffer(key_index, clear_buffer_, &signature);
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_SelectKey(session_.session_id(),
session_.license().keys[key_index].key_id,
session_.license().keys[key_index].key_id_length));
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_Generic_Verify(
session_.session_id(), &clear_buffer_[0], clear_buffer_.size(),
OEMCrypto_HMAC_SHA256, &signature[0], signature.size()));
}
TEST_F(GenericCryptoTest, KeyDurationEncrypt) {
EncryptAndLoadKeys();
vector<uint8_t> expected_encrypted;