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:
@@ -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,
|
||||
¤t_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,
|
||||
¤t_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,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user