Fix a few problems in AesCryptor classes
- CBC cryptors should accept IV of size 8 bytes - it will be zero extended to 16 bytes. - Fixed iv() not updated problem in AesPatternCryptor. - Replace kChainAcrossCalls with ConstantIvFlag enum flags. Change-Id: I3fb4de0e8abbe891e6271e779373ba53f8df660d
This commit is contained in:
parent
66b82f87dd
commit
13202f91b6
|
@ -50,6 +50,14 @@ bool ValidateFixedCryptoFlags() {
|
|||
"--enable_fixed_key_encryption")) {
|
||||
success = false;
|
||||
}
|
||||
if (!FLAGS_iv.empty()) {
|
||||
if (FLAGS_iv.size() != 8 * 2 && FLAGS_iv.size() != 16 * 2) {
|
||||
PrintError(
|
||||
"--iv should be either 8 bytes (16 hex digits) or 16 bytes (32 hex "
|
||||
"digits).");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// --pssh is associated with --enable_fix_key_encryption.
|
||||
if (!ValidateFlag("pssh",
|
||||
|
|
|
@ -384,12 +384,6 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
|||
const FourCC protection_scheme = GetProtectionScheme(FLAGS_protection_scheme);
|
||||
if (protection_scheme == FOURCC_NULL)
|
||||
return false;
|
||||
if (protection_scheme == FOURCC_cbc1 || protection_scheme == FOURCC_cbcs) {
|
||||
if (!FLAGS_iv.empty() && FLAGS_iv.size() != 16) {
|
||||
LOG(ERROR) << "Iv size should be 16 bytes for CBC encryption mode.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AssignFlagsFromProfile())
|
||||
return false;
|
||||
|
|
|
@ -61,7 +61,7 @@ DEFINE_string(protection_scheme,
|
|||
"protection schemes 'cens' or 'cbcs'. Note that if a "
|
||||
"pattern-based protection scheme only applies to video stream; "
|
||||
"audio stream will be encrypted using the corresponding "
|
||||
"non-pattern-based encryption schemes, i.e. 'cenc' for 'cens', "
|
||||
"non-pattern-based protection schemes, i.e. 'cenc' for 'cens', "
|
||||
"'cbc1' for 'cbcs'.");
|
||||
|
||||
namespace edash_packager {
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include "packager/media/base/aes_cryptor.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
|
@ -13,10 +16,24 @@
|
|||
#include "packager/base/logging.h"
|
||||
#include "packager/base/stl_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// According to ISO/IEC 23001-7:2016 CENC spec, IV should be either
|
||||
// 64-bit (8-byte) or 128-bit (16-byte).
|
||||
bool IsIvSizeValid(size_t iv_size) {
|
||||
return iv_size == 8 || iv_size == 16;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
AesCryptor::AesCryptor() : aes_key_(new AES_KEY) {}
|
||||
AesCryptor::AesCryptor(ConstantIvFlag constant_iv_flag)
|
||||
: aes_key_(new AES_KEY),
|
||||
constant_iv_flag_(constant_iv_flag),
|
||||
num_crypt_bytes_(0) {}
|
||||
|
||||
AesCryptor::~AesCryptor() {}
|
||||
|
||||
bool AesCryptor::Crypt(const std::vector<uint8_t>& text,
|
||||
|
@ -26,8 +43,7 @@ bool AesCryptor::Crypt(const std::vector<uint8_t>& text,
|
|||
const size_t text_size = text.size();
|
||||
crypt_text->resize(text_size + NumPaddingBytes(text_size));
|
||||
size_t crypt_text_size = crypt_text->size();
|
||||
if (!CryptInternal(text.data(), text_size, crypt_text->data(),
|
||||
&crypt_text_size)) {
|
||||
if (!Crypt(text.data(), text_size, crypt_text->data(), &crypt_text_size)) {
|
||||
return false;
|
||||
}
|
||||
DCHECK_LE(crypt_text_size, crypt_text->size());
|
||||
|
@ -41,7 +57,7 @@ bool AesCryptor::Crypt(const std::string& text, std::string* crypt_text) {
|
|||
const size_t text_size = text.size();
|
||||
crypt_text->resize(text_size + NumPaddingBytes(text_size));
|
||||
size_t crypt_text_size = crypt_text->size();
|
||||
if (!CryptInternal(reinterpret_cast<const uint8_t*>(text.data()), text_size,
|
||||
if (!Crypt(reinterpret_cast<const uint8_t*>(text.data()), text_size,
|
||||
reinterpret_cast<uint8_t*>(string_as_array(crypt_text)),
|
||||
&crypt_text_size))
|
||||
return false;
|
||||
|
@ -50,9 +66,44 @@ bool AesCryptor::Crypt(const std::string& text, std::string* crypt_text) {
|
|||
return true;
|
||||
}
|
||||
|
||||
size_t AesCryptor::NumPaddingBytes(size_t size) const {
|
||||
// No padding by default.
|
||||
return 0;
|
||||
bool AesCryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (!IsIvSizeValid(iv.size())) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
iv_ = iv;
|
||||
num_crypt_bytes_ = 0;
|
||||
SetIvInternal();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCryptor::UpdateIv() {
|
||||
if (constant_iv_flag_ == kUseConstantIv)
|
||||
return;
|
||||
|
||||
uint64_t increment = 0;
|
||||
// As recommended in ISO/IEC 23001-7:2016 CENC spec, for 64-bit (8-byte)
|
||||
// IV_Sizes, initialization vectors for subsequent samples can be created by
|
||||
// incrementing the initialization vector of the previous sample.
|
||||
// For 128-bit (16-byte) IV_Sizes, initialization vectors for subsequent
|
||||
// samples should be created by adding the block count of the previous sample
|
||||
// to the initialization vector of the previous sample.
|
||||
// There is no official recommendation of how IV for next sample should be
|
||||
// generated for CBC mode. We use the same generation algorithm as CTR here.
|
||||
if (iv_.size() == 8) {
|
||||
increment = 1;
|
||||
} else {
|
||||
DCHECK_EQ(16u, iv_.size());
|
||||
increment = (num_crypt_bytes_ + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
for (int i = iv_.size() - 1; increment > 0 && i >= 0; --i) {
|
||||
increment += iv_[i];
|
||||
iv_[i] = increment & 0xFF;
|
||||
increment >>= 8;
|
||||
}
|
||||
num_crypt_bytes_ = 0;
|
||||
SetIvInternal();
|
||||
}
|
||||
|
||||
bool AesCryptor::GenerateRandomIv(FourCC protection_scheme,
|
||||
|
@ -74,6 +125,11 @@ bool AesCryptor::GenerateRandomIv(FourCC protection_scheme,
|
|||
return true;
|
||||
}
|
||||
|
||||
size_t AesCryptor::NumPaddingBytes(size_t size) const {
|
||||
// No padding by default.
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
||||
|
|
|
@ -24,7 +24,18 @@ namespace media {
|
|||
// implementations.
|
||||
class AesCryptor {
|
||||
public:
|
||||
AesCryptor();
|
||||
enum ConstantIvFlag {
|
||||
kUseConstantIv,
|
||||
kDontUseConstantIv,
|
||||
};
|
||||
|
||||
/// @param constant_iv_flag indicates whether a constant iv is used,
|
||||
/// kUseConstantIv means that the same iv is used for all Crypt calls
|
||||
/// until iv is changed via SetIv; otherwise, iv can be incremented
|
||||
/// (for counter mode) or chained (for cipher block chaining mode)
|
||||
/// internally inside Crypt call, i.e. iv will be updated across Crypt
|
||||
/// calls.
|
||||
explicit AesCryptor(ConstantIvFlag constant_iv_flag);
|
||||
virtual ~AesCryptor();
|
||||
|
||||
/// Initialize the cryptor with specified key and IV.
|
||||
|
@ -43,18 +54,28 @@ class AesCryptor {
|
|||
/// @param crypt_text should have at least @a text_size bytes.
|
||||
bool Crypt(const uint8_t* text, size_t text_size, uint8_t* crypt_text) {
|
||||
size_t crypt_text_size = text_size;
|
||||
return CryptInternal(text, text_size, crypt_text, &crypt_text_size);
|
||||
return Crypt(text, text_size, crypt_text, &crypt_text_size);
|
||||
}
|
||||
bool Crypt(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size) {
|
||||
if (constant_iv_flag_ == kUseConstantIv)
|
||||
SetIvInternal();
|
||||
else
|
||||
num_crypt_bytes_ += text_size;
|
||||
return CryptInternal(text, text_size, crypt_text, crypt_text_size);
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// Set IV.
|
||||
/// @return true if successful, false if the input is invalid.
|
||||
virtual bool SetIv(const std::vector<uint8_t>& iv) = 0;
|
||||
bool SetIv(const std::vector<uint8_t>& iv);
|
||||
|
||||
/// Update IV for next sample. As recommended in ISO/IEC 23001-7: IV need to
|
||||
/// be updated per sample for CENC.
|
||||
/// This is used by encryptors only.
|
||||
virtual void UpdateIv() = 0;
|
||||
/// This is used by encryptors only. It is a NOP if using kUseConstantIv.
|
||||
void UpdateIv();
|
||||
|
||||
/// @return The current iv.
|
||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||
|
@ -67,7 +88,6 @@ class AesCryptor {
|
|||
std::vector<uint8_t>* iv);
|
||||
|
||||
protected:
|
||||
void set_iv(const std::vector<uint8_t>& iv) { iv_ = iv; }
|
||||
const AES_KEY* aes_key() const { return aes_key_.get(); }
|
||||
AES_KEY* mutable_aes_key() { return aes_key_.get(); }
|
||||
|
||||
|
@ -87,16 +107,27 @@ class AesCryptor {
|
|||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size) = 0;
|
||||
|
||||
// Internal implementation of SetIv, which setup internal iv.
|
||||
virtual void SetIvInternal() = 0;
|
||||
|
||||
// |size| specifies the input text size.
|
||||
// Return the number of padding bytes needed.
|
||||
// Note: No paddings should be needed except for pkcs5-cbc encryptor.
|
||||
virtual size_t NumPaddingBytes(size_t size) const;
|
||||
|
||||
// Initialization vector, with size 8 or 16.
|
||||
std::vector<uint8_t> iv_;
|
||||
// Openssl AES_KEY.
|
||||
scoped_ptr<AES_KEY> aes_key_;
|
||||
|
||||
// Indicates whether a constant iv is used. Internal iv will be reset to
|
||||
// |iv_| before calling Crypt if that is the case.
|
||||
const ConstantIvFlag constant_iv_flag_;
|
||||
// Initialization vector from by SetIv or InitializeWithIv, with size 8 or 16
|
||||
// bytes.
|
||||
std::vector<uint8_t> iv_;
|
||||
// Tracks number of crypt bytes. It is used to calculate how many blocks
|
||||
// should iv advance in UpdateIv(). It will be reset to 0 after iv is updated.
|
||||
size_t num_crypt_bytes_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCryptor);
|
||||
};
|
||||
|
||||
|
|
|
@ -220,6 +220,20 @@ TEST_F(AesCtrEncryptorTest, 128BitIVBoundaryCaseEncryption) {
|
|||
EXPECT_EQ(encrypted, encrypted_verify);
|
||||
}
|
||||
|
||||
TEST_F(AesCtrEncryptorTest, 64BitIvUpdate) {
|
||||
std::vector<uint8_t> iv_zero(kIv64Zero, kIv64Zero + arraysize(kIv64Zero));
|
||||
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_zero));
|
||||
|
||||
// There are four blocks of text in |plaintext_|, but since iv is 8 bytes,
|
||||
// iv should only be incremented by one when UpdateIv() is called.
|
||||
std::vector<uint8_t> encrypted;
|
||||
ASSERT_TRUE(encryptor_.Crypt(plaintext_, &encrypted));
|
||||
|
||||
std::vector<uint8_t> iv_one(kIv64One, kIv64One + arraysize(kIv64One));
|
||||
encryptor_.UpdateIv();
|
||||
EXPECT_EQ(iv_one, encryptor_.iv());
|
||||
}
|
||||
|
||||
TEST_F(AesCtrEncryptorTest, GenerateRandomIv) {
|
||||
const uint8_t kCencIvSize = 8;
|
||||
std::vector<uint8_t> iv;
|
||||
|
@ -297,8 +311,10 @@ INSTANTIATE_TEST_CASE_P(IvTestCases,
|
|||
class AesCbcTest : public ::testing::Test {
|
||||
public:
|
||||
AesCbcTest()
|
||||
: encryptor_(new AesCbcEncryptor(kPkcs5Padding, !kChainAcrossCalls)),
|
||||
decryptor_(new AesCbcDecryptor(kPkcs5Padding, !kChainAcrossCalls)),
|
||||
: encryptor_(
|
||||
new AesCbcEncryptor(kPkcs5Padding, AesCryptor::kUseConstantIv)),
|
||||
decryptor_(
|
||||
new AesCbcDecryptor(kPkcs5Padding, AesCryptor::kUseConstantIv)),
|
||||
key_(kAesKey, kAesKey + arraysize(kAesKey)),
|
||||
iv_(kAesIv, kAesIv + arraysize(kAesIv)) {}
|
||||
|
||||
|
@ -450,25 +466,21 @@ TEST_F(AesCbcTest, NoPaddingNoChainAcrossCalls) {
|
|||
std::vector<uint8_t> ciphertext(kCiphertext,
|
||||
kCiphertext + arraysize(kCiphertext));
|
||||
|
||||
AesCbcEncryptor encryptor(kNoPadding, !kChainAcrossCalls);
|
||||
AesCbcEncryptor encryptor(kNoPadding, AesCryptor::kUseConstantIv);
|
||||
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
||||
|
||||
std::vector<uint8_t> encrypted;
|
||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||
EXPECT_EQ(ciphertext, encrypted);
|
||||
// Iv should not have been updated.
|
||||
EXPECT_EQ(iv_, encryptor.iv());
|
||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||
EXPECT_EQ(ciphertext, encrypted);
|
||||
|
||||
AesCbcDecryptor decryptor(kNoPadding, !kChainAcrossCalls);
|
||||
AesCbcDecryptor decryptor(kNoPadding, AesCryptor::kUseConstantIv);
|
||||
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
||||
|
||||
std::vector<uint8_t> decrypted;
|
||||
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
// Iv should not have been updated.
|
||||
EXPECT_EQ(iv_, encryptor.iv());
|
||||
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
}
|
||||
|
@ -494,26 +506,23 @@ TEST_F(AesCbcTest, NoPaddingChainAcrossCalls) {
|
|||
std::vector<uint8_t> ciphertext2(kCiphertext2,
|
||||
kCiphertext2 + arraysize(kCiphertext2));
|
||||
|
||||
AesCbcEncryptor encryptor(kNoPadding, kChainAcrossCalls);
|
||||
AesCbcEncryptor encryptor(kNoPadding, AesCryptor::kDontUseConstantIv);
|
||||
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
||||
|
||||
std::vector<uint8_t> encrypted;
|
||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||
EXPECT_EQ(ciphertext, encrypted);
|
||||
// Iv should have been updated.
|
||||
EXPECT_NE(iv_, encryptor.iv());
|
||||
// If run encrypt again, the result will be different.
|
||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||
EXPECT_NE(ciphertext, ciphertext2);
|
||||
EXPECT_EQ(ciphertext2, encrypted);
|
||||
|
||||
AesCbcDecryptor decryptor(kNoPadding, kChainAcrossCalls);
|
||||
AesCbcDecryptor decryptor(kNoPadding, AesCryptor::kDontUseConstantIv);
|
||||
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
||||
|
||||
std::vector<uint8_t> decrypted;
|
||||
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
// Iv should have been updated.
|
||||
EXPECT_NE(iv_, encryptor.iv());
|
||||
// If run decrypt on ciphertext2 now, it will return the original plaintext.
|
||||
ASSERT_TRUE(decryptor.Crypt(ciphertext2, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
|
@ -524,9 +533,11 @@ TEST_F(AesCbcTest, UnsupportedKeySize) {
|
|||
EXPECT_FALSE(decryptor_->InitializeWithIv(std::vector<uint8_t>(15, 0), iv_));
|
||||
}
|
||||
|
||||
TEST_F(AesCbcTest, UnsupportedIvSize) {
|
||||
TEST_F(AesCbcTest, VariousIvSize) {
|
||||
EXPECT_FALSE(encryptor_->InitializeWithIv(key_, std::vector<uint8_t>(14, 0)));
|
||||
EXPECT_FALSE(decryptor_->InitializeWithIv(key_, std::vector<uint8_t>(8, 0)));
|
||||
EXPECT_FALSE(decryptor_->InitializeWithIv(key_, std::vector<uint8_t>(7, 0)));
|
||||
EXPECT_FALSE(decryptor_->InitializeWithIv(key_, std::vector<uint8_t>(1, 0)));
|
||||
EXPECT_TRUE(decryptor_->InitializeWithIv(key_, std::vector<uint8_t>(8, 0)));
|
||||
}
|
||||
|
||||
TEST_F(AesCbcTest, Pkcs5CipherTextNotMultipleOfBlockSize) {
|
||||
|
@ -584,10 +595,10 @@ class AesCbcCryptorVerificationTest
|
|||
public ::testing::WithParamInterface<CbcTestCase> {};
|
||||
|
||||
TEST_P(AesCbcCryptorVerificationTest, EncryptDecryptTest) {
|
||||
encryptor_.reset(
|
||||
new AesCbcEncryptor(GetParam().padding_scheme, !kChainAcrossCalls));
|
||||
decryptor_.reset(
|
||||
new AesCbcDecryptor(GetParam().padding_scheme, !kChainAcrossCalls));
|
||||
encryptor_.reset(new AesCbcEncryptor(GetParam().padding_scheme,
|
||||
AesCryptor::kUseConstantIv));
|
||||
decryptor_.reset(new AesCbcDecryptor(GetParam().padding_scheme,
|
||||
AesCryptor::kUseConstantIv));
|
||||
|
||||
std::vector<uint8_t> plaintext;
|
||||
std::string plaintext_hex(GetParam().plaintext_hex);
|
||||
|
|
|
@ -22,13 +22,16 @@ bool IsKeySizeValidForAes(size_t key_size) {
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme)
|
||||
: AesCbcDecryptor(padding_scheme, kDontUseConstantIv) {}
|
||||
|
||||
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
|
||||
bool chain_across_calls)
|
||||
: padding_scheme_(padding_scheme),
|
||||
chain_across_calls_(chain_across_calls) {
|
||||
ConstantIvFlag constant_iv_flag)
|
||||
: AesCryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
|
||||
if (padding_scheme_ != kNoPadding) {
|
||||
CHECK(!chain_across_calls) << "cipher block chain across calls only makes "
|
||||
"sense if the padding_scheme is kNoPadding.";
|
||||
CHECK_EQ(constant_iv_flag, kUseConstantIv)
|
||||
<< "non-constant iv (cipher block chain across calls) only makes sense "
|
||||
"if the padding_scheme is kNoPadding.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,16 +49,6 @@ bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
|||
return SetIv(iv);
|
||||
}
|
||||
|
||||
bool AesCbcDecryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
set_iv(iv);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
||||
size_t ciphertext_size,
|
||||
uint8_t* plaintext,
|
||||
|
@ -82,14 +75,11 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
|||
}
|
||||
DCHECK(plaintext);
|
||||
|
||||
std::vector<uint8_t> local_iv(iv());
|
||||
const size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
|
||||
const size_t cbc_size = ciphertext_size - residual_block_size;
|
||||
if (residual_block_size == 0) {
|
||||
AES_cbc_encrypt(ciphertext, plaintext, ciphertext_size, aes_key(),
|
||||
local_iv.data(), AES_DECRYPT);
|
||||
if (chain_across_calls_)
|
||||
set_iv(local_iv);
|
||||
internal_iv_.data(), AES_DECRYPT);
|
||||
if (padding_scheme_ != kPkcs5Padding)
|
||||
return true;
|
||||
|
||||
|
@ -103,10 +93,8 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
|||
*plaintext_size -= num_padding_bytes;
|
||||
return true;
|
||||
} else if (padding_scheme_ == kNoPadding) {
|
||||
AES_cbc_encrypt(ciphertext, plaintext, cbc_size, aes_key(), local_iv.data(),
|
||||
AES_DECRYPT);
|
||||
if (chain_across_calls_)
|
||||
set_iv(local_iv);
|
||||
AES_cbc_encrypt(ciphertext, plaintext, cbc_size, aes_key(),
|
||||
internal_iv_.data(), AES_DECRYPT);
|
||||
|
||||
// The residual block is not encrypted.
|
||||
memcpy(plaintext + cbc_size, ciphertext + cbc_size, residual_block_size);
|
||||
|
@ -117,7 +105,6 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
|||
return false;
|
||||
}
|
||||
|
||||
DCHECK(!chain_across_calls_);
|
||||
DCHECK_EQ(padding_scheme_, kCtsPadding);
|
||||
if (ciphertext_size < AES_BLOCK_SIZE) {
|
||||
// Don't have a full block, leave unencrypted.
|
||||
|
@ -128,7 +115,7 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
|||
// AES-CBC decrypt everything up to the next-to-last full block.
|
||||
if (cbc_size > AES_BLOCK_SIZE) {
|
||||
AES_cbc_encrypt(ciphertext, plaintext, cbc_size - AES_BLOCK_SIZE, aes_key(),
|
||||
local_iv.data(), AES_DECRYPT);
|
||||
internal_iv_.data(), AES_DECRYPT);
|
||||
}
|
||||
|
||||
const uint8_t* next_to_last_ciphertext_block =
|
||||
|
@ -162,9 +149,14 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
|||
|
||||
// Decrypt the next-to-last full block.
|
||||
AES_cbc_encrypt(next_to_last_plaintext_block, next_to_last_plaintext_block,
|
||||
AES_BLOCK_SIZE, aes_key(), local_iv.data(), AES_DECRYPT);
|
||||
AES_BLOCK_SIZE, aes_key(), internal_iv_.data(), AES_DECRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesCbcDecryptor::SetIvInternal() {
|
||||
internal_iv_ = iv();
|
||||
internal_iv_.resize(AES_BLOCK_SIZE, 0);
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -24,22 +24,28 @@ using AesCtrDecryptor = AesCtrEncryptor;
|
|||
/// Class which implements AES-CBC (Cipher block chaining) decryption.
|
||||
class AesCbcDecryptor : public AesCryptor {
|
||||
public:
|
||||
/// Creates a AesCbcDecryptor with continous cipher block chain across Crypt
|
||||
/// calls.
|
||||
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
||||
/// @param chain_across_calls indicates whether there is a continuous cipher
|
||||
/// block chain across calls for Decrypt function. If it is false, iv
|
||||
/// is not updated across Decrypt function calls.
|
||||
AesCbcDecryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls);
|
||||
explicit AesCbcDecryptor(CbcPaddingScheme padding_scheme);
|
||||
|
||||
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
||||
/// @param constant_iv_flag indicates whether a constant iv is used,
|
||||
/// kUseConstantIv means that the same iv is used for all Crypt calls
|
||||
/// until iv is changed via SetIv; otherwise, iv is updated internally
|
||||
/// and there is a continuous cipher block chain across Crypt calls
|
||||
/// util iv is changed explicitly via SetIv or UpdateIv functions.
|
||||
AesCbcDecryptor(CbcPaddingScheme padding_scheme,
|
||||
ConstantIvFlag constant_iv_flag);
|
||||
|
||||
~AesCbcDecryptor() override;
|
||||
|
||||
/// @name AesCryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
void UpdateIv() override {
|
||||
// Nop for decryptor.
|
||||
}
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
@ -47,9 +53,11 @@ class AesCbcDecryptor : public AesCryptor {
|
|||
size_t ciphertext_size,
|
||||
uint8_t* plaintext,
|
||||
size_t* plaintext_size) override;
|
||||
void SetIvInternal() override;
|
||||
|
||||
const CbcPaddingScheme padding_scheme_;
|
||||
const bool chain_across_calls_;
|
||||
// 16-byte internal iv for crypto operations.
|
||||
std::vector<uint8_t> internal_iv_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcDecryptor);
|
||||
};
|
||||
|
|
|
@ -15,16 +15,13 @@ namespace {
|
|||
// Increment an 8-byte counter by 1. Return true if overflowed.
|
||||
bool Increment64(uint8_t* counter) {
|
||||
DCHECK(counter);
|
||||
for (int i = 7; i >= 0; --i)
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
if (++counter[i] != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
|
||||
// 64-bit (8-byte) or 128-bit (16-byte).
|
||||
bool IsIvSizeValid(size_t iv_size) { return iv_size == 8 || iv_size == 16; }
|
||||
|
||||
// AES defines three key sizes: 128, 192 and 256 bits.
|
||||
bool IsKeySizeValidForAes(size_t key_size) {
|
||||
return key_size == 16 || key_size == 24 || key_size == 32;
|
||||
|
@ -35,7 +32,8 @@ bool IsKeySizeValidForAes(size_t key_size) {
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
AesEncryptor::AesEncryptor() {}
|
||||
AesEncryptor::AesEncryptor(ConstantIvFlag constant_iv_flag)
|
||||
: AesCryptor(constant_iv_flag) {}
|
||||
AesEncryptor::~AesEncryptor() {}
|
||||
|
||||
bool AesEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
|
@ -50,55 +48,15 @@ bool AesEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
|||
return SetIv(iv);
|
||||
}
|
||||
|
||||
// We don't support constant iv for counter mode, as we don't have a use case
|
||||
// for that.
|
||||
AesCtrEncryptor::AesCtrEncryptor()
|
||||
: block_offset_(0),
|
||||
encrypted_counter_(AES_BLOCK_SIZE, 0),
|
||||
counter_overflow_(false) {}
|
||||
: AesEncryptor(kDontUseConstantIv),
|
||||
block_offset_(0),
|
||||
encrypted_counter_(AES_BLOCK_SIZE, 0) {}
|
||||
|
||||
AesCtrEncryptor::~AesCtrEncryptor() {}
|
||||
|
||||
void AesCtrEncryptor::UpdateIv() {
|
||||
block_offset_ = 0;
|
||||
|
||||
// As recommended in ISO/IEC FDIS 23001-7: CENC spec, for 64-bit (8-byte)
|
||||
// IV_Sizes, initialization vectors for subsequent samples can be created by
|
||||
// incrementing the initialization vector of the previous sample.
|
||||
// For 128-bit (16-byte) IV_Sizes, initialization vectors for subsequent
|
||||
// samples should be created by adding the block count of the previous sample
|
||||
// to the initialization vector of the previous sample.
|
||||
if (iv().size() == 8) {
|
||||
counter_ = iv();
|
||||
Increment64(&counter_[0]);
|
||||
set_iv(counter_);
|
||||
counter_.resize(AES_BLOCK_SIZE, 0);
|
||||
} else {
|
||||
DCHECK_EQ(16u, iv().size());
|
||||
// Even though the block counter portion of the counter (bytes 8 to 15) is
|
||||
// treated as a 64-bit number, it is recommended that the initialization
|
||||
// vector is treated as a 128-bit number when calculating the next
|
||||
// initialization vector from the previous one. The block counter portion
|
||||
// is already incremented by number of blocks, the other 64 bits of the
|
||||
// counter (bytes 0 to 7) is incremented here if the block counter portion
|
||||
// has overflowed.
|
||||
if (counter_overflow_)
|
||||
Increment64(&counter_[0]);
|
||||
set_iv(counter_);
|
||||
}
|
||||
counter_overflow_ = false;
|
||||
}
|
||||
|
||||
bool AesCtrEncryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (!IsIvSizeValid(iv.size())) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
block_offset_ = 0;
|
||||
set_iv(iv);
|
||||
counter_ = iv;
|
||||
counter_.resize(AES_BLOCK_SIZE, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
|
@ -119,13 +77,12 @@ bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
|
|||
for (size_t i = 0; i < plaintext_size; ++i) {
|
||||
if (block_offset_ == 0) {
|
||||
AES_encrypt(&counter_[0], &encrypted_counter_[0], aes_key());
|
||||
// As mentioned in ISO/IEC FDIS 23001-7: CENC spec, of the 16 byte counter
|
||||
// As mentioned in ISO/IEC 23001-7:2016 CENC spec, of the 16 byte counter
|
||||
// block, bytes 8 to 15 (i.e. the least significant bytes) are used as a
|
||||
// simple 64 bit unsigned integer that is incremented by one for each
|
||||
// subsequent block of sample data processed and is kept in network byte
|
||||
// order.
|
||||
if (Increment64(&counter_[8]))
|
||||
counter_overflow_ = true;
|
||||
Increment64(&counter_[8]);
|
||||
}
|
||||
ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
|
||||
block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
|
||||
|
@ -133,37 +90,27 @@ bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
|
|||
return true;
|
||||
}
|
||||
|
||||
void AesCtrEncryptor::SetIvInternal() {
|
||||
block_offset_ = 0;
|
||||
counter_ = iv();
|
||||
counter_.resize(AES_BLOCK_SIZE, 0);
|
||||
}
|
||||
|
||||
AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme)
|
||||
: AesCbcEncryptor(padding_scheme, kDontUseConstantIv) {}
|
||||
|
||||
AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme,
|
||||
bool chain_across_calls)
|
||||
: padding_scheme_(padding_scheme),
|
||||
chain_across_calls_(chain_across_calls) {
|
||||
ConstantIvFlag constant_iv_flag)
|
||||
: AesEncryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
|
||||
if (padding_scheme_ != kNoPadding) {
|
||||
CHECK(!chain_across_calls) << "cipher block chain across calls only makes "
|
||||
"sense if the padding_scheme is kNoPadding.";
|
||||
CHECK_EQ(constant_iv_flag, kUseConstantIv)
|
||||
<< "non-constant iv (cipher block chain across calls) only makes sense "
|
||||
"if the padding_scheme is kNoPadding.";
|
||||
}
|
||||
}
|
||||
|
||||
AesCbcEncryptor::~AesCbcEncryptor() {}
|
||||
|
||||
void AesCbcEncryptor::UpdateIv() {
|
||||
// From CENC spec: CBC mode Initialization Vectors need not be unique per
|
||||
// sample or Subsample and may be generated randomly or sequentially, e.g.
|
||||
// a per sample IV may be (1) equal to the cipher text of the last encrypted
|
||||
// cipher block (a continous cipher block chain across samples), or (2)
|
||||
// generated by incrementing the previuos IV by the number of cipher blocks in the last
|
||||
// sample or (3) by a fixed amount. We use method (1) here. No separate IV
|
||||
// update is needed.
|
||||
}
|
||||
|
||||
bool AesCbcEncryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
if (iv.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
set_iv(iv);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext,
|
||||
|
@ -182,22 +129,18 @@ bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
|||
|
||||
// Encrypt everything but the residual block using CBC.
|
||||
const size_t cbc_size = plaintext_size - residual_block_size;
|
||||
std::vector<uint8_t> local_iv(iv());
|
||||
if (cbc_size != 0) {
|
||||
AES_cbc_encrypt(plaintext, ciphertext, cbc_size, aes_key(), local_iv.data(),
|
||||
AES_ENCRYPT);
|
||||
AES_cbc_encrypt(plaintext, ciphertext, cbc_size, aes_key(),
|
||||
internal_iv_.data(), AES_ENCRYPT);
|
||||
} else if (padding_scheme_ == kCtsPadding) {
|
||||
// Don't have a full block, leave unencrypted.
|
||||
memcpy(ciphertext, plaintext, plaintext_size);
|
||||
return true;
|
||||
}
|
||||
if (residual_block_size == 0 && padding_scheme_ != kPkcs5Padding) {
|
||||
if (chain_across_calls_)
|
||||
set_iv(local_iv);
|
||||
// No residual block. No need to do padding.
|
||||
return true;
|
||||
}
|
||||
DCHECK(!chain_across_calls_);
|
||||
|
||||
if (padding_scheme_ == kNoPadding) {
|
||||
// The residual block is left unencrypted.
|
||||
|
@ -216,7 +159,8 @@ bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
|||
// Pad residue block with PKCS5 padding.
|
||||
residual_block.resize(AES_BLOCK_SIZE, static_cast<char>(num_padding_bytes));
|
||||
AES_cbc_encrypt(residual_block.data(), residual_ciphertext_block,
|
||||
AES_BLOCK_SIZE, aes_key(), local_iv.data(), AES_ENCRYPT);
|
||||
AES_BLOCK_SIZE, aes_key(), internal_iv_.data(),
|
||||
AES_ENCRYPT);
|
||||
} else {
|
||||
DCHECK_EQ(num_padding_bytes, 0u);
|
||||
DCHECK_EQ(padding_scheme_, kCtsPadding);
|
||||
|
@ -224,7 +168,8 @@ bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
|||
// Zero-pad the residual block and encrypt using CBC.
|
||||
residual_block.resize(AES_BLOCK_SIZE, 0);
|
||||
AES_cbc_encrypt(residual_block.data(), residual_block.data(),
|
||||
AES_BLOCK_SIZE, aes_key(), local_iv.data(), AES_ENCRYPT);
|
||||
AES_BLOCK_SIZE, aes_key(), internal_iv_.data(),
|
||||
AES_ENCRYPT);
|
||||
|
||||
// Replace the last full block with the zero-padded, encrypted residual
|
||||
// block, and replace the residual block with the equivalent portion of the
|
||||
|
@ -239,6 +184,11 @@ bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
|||
return true;
|
||||
}
|
||||
|
||||
void AesCbcEncryptor::SetIvInternal() {
|
||||
internal_iv_ = iv();
|
||||
internal_iv_.resize(AES_BLOCK_SIZE, 0);
|
||||
}
|
||||
|
||||
size_t AesCbcEncryptor::NumPaddingBytes(size_t size) const {
|
||||
return (padding_scheme_ == kPkcs5Padding)
|
||||
? (AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE))
|
||||
|
|
|
@ -21,7 +21,13 @@ namespace media {
|
|||
|
||||
class AesEncryptor : public AesCryptor {
|
||||
public:
|
||||
AesEncryptor();
|
||||
/// @param constant_iv_flag indicates whether a constant iv is used,
|
||||
/// kUseConstantIv means that the same iv is used for all Crypt calls
|
||||
/// until iv is changed via SetIv; otherwise, iv can be incremented
|
||||
/// (for counter mode) or chained (for cipher block chaining mode)
|
||||
/// internally inside Crypt call, i.e. iv will be updated across Crypt
|
||||
/// calls.
|
||||
explicit AesEncryptor(ConstantIvFlag constant_iv_flag);
|
||||
~AesEncryptor() override;
|
||||
|
||||
/// Initialize the encryptor with specified key and IV.
|
||||
|
@ -39,17 +45,6 @@ class AesCtrEncryptor : public AesEncryptor {
|
|||
AesCtrEncryptor();
|
||||
~AesCtrEncryptor() override;
|
||||
|
||||
/// @name AesCryptor implementation overrides.
|
||||
/// @{
|
||||
/// Update IV for next sample. @a block_offset_ is reset to 0.
|
||||
/// As recommended in ISO/IEC FDIS 23001-7: CENC spec,
|
||||
/// For 64-bit IV size, new_iv = old_iv + 1;
|
||||
/// For 128-bit IV size, new_iv = old_iv + previous_sample_block_count.
|
||||
void UpdateIv() override;
|
||||
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
uint32_t block_offset() const { return block_offset_; }
|
||||
|
||||
private:
|
||||
|
@ -57,6 +52,7 @@ class AesCtrEncryptor : public AesEncryptor {
|
|||
size_t plaintext_size,
|
||||
uint8_t* ciphertext,
|
||||
size_t* ciphertext_size) override;
|
||||
void SetIvInternal() override;
|
||||
|
||||
// Current block offset.
|
||||
uint32_t block_offset_;
|
||||
|
@ -64,8 +60,6 @@ class AesCtrEncryptor : public AesEncryptor {
|
|||
std::vector<uint8_t> counter_;
|
||||
// Encrypted counter.
|
||||
std::vector<uint8_t> encrypted_counter_;
|
||||
// Keep track of whether the counter has overflowed.
|
||||
bool counter_overflow_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCtrEncryptor);
|
||||
};
|
||||
|
@ -80,35 +74,38 @@ enum CbcPaddingScheme {
|
|||
kCtsPadding,
|
||||
};
|
||||
|
||||
const bool kChainAcrossCalls = true;
|
||||
|
||||
// Class which implements AES-CBC (Cipher block chaining) encryption.
|
||||
class AesCbcEncryptor : public AesEncryptor {
|
||||
public:
|
||||
/// Creates a AesCbcEncryptor with continous cipher block chain across Crypt
|
||||
/// calls, i.e. AesCbcEncryptor(padding_scheme, kDontUseConstantIv).
|
||||
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
||||
/// @param chain_across_calls indicates whether there is a continuous cipher
|
||||
/// block chain across calls for Encrypt function. If it is false, iv
|
||||
/// is not updated across Encrypt function calls.
|
||||
AesCbcEncryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls);
|
||||
explicit AesCbcEncryptor(CbcPaddingScheme padding_scheme);
|
||||
|
||||
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
||||
/// @param constant_iv_flag indicates whether a constant iv is used,
|
||||
/// kUseConstantIv means that the same iv is used for all Crypt calls
|
||||
/// until iv is changed via SetIv; otherwise, iv is updated internally
|
||||
/// and there is a continuous cipher block chain across Crypt calls
|
||||
/// util iv is changed explicitly via SetIv or UpdateIv functions.
|
||||
AesCbcEncryptor(CbcPaddingScheme padding_scheme,
|
||||
ConstantIvFlag constant_iv_flag);
|
||||
|
||||
~AesCbcEncryptor() override;
|
||||
|
||||
/// @name AesCryptor implementation overrides.
|
||||
/// @{
|
||||
void UpdateIv() override;
|
||||
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
bool CryptInternal(const uint8_t* plaintext,
|
||||
size_t plaintext_size,
|
||||
uint8_t* ciphertext,
|
||||
size_t* ciphertext_size) override;
|
||||
void SetIvInternal() override;
|
||||
size_t NumPaddingBytes(size_t size) const override;
|
||||
|
||||
const CbcPaddingScheme padding_scheme_;
|
||||
const bool chain_across_calls_;
|
||||
// 16-byte internal iv for crypto operations.
|
||||
std::vector<uint8_t> internal_iv_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesCbcEncryptor);
|
||||
};
|
||||
|
|
|
@ -17,9 +17,9 @@ AesPatternCryptor::AesPatternCryptor(uint8_t crypt_byte_block,
|
|||
uint8_t skip_byte_block,
|
||||
ConstantIvFlag constant_iv_flag,
|
||||
scoped_ptr<AesCryptor> cryptor)
|
||||
: crypt_byte_block_(crypt_byte_block),
|
||||
: AesCryptor(constant_iv_flag),
|
||||
crypt_byte_block_(crypt_byte_block),
|
||||
skip_byte_block_(skip_byte_block),
|
||||
constant_iv_flag_(constant_iv_flag),
|
||||
cryptor_(cryptor.Pass()) {
|
||||
DCHECK(cryptor_);
|
||||
}
|
||||
|
@ -28,26 +28,13 @@ AesPatternCryptor::~AesPatternCryptor() {}
|
|||
|
||||
bool AesPatternCryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
iv_ = iv;
|
||||
return cryptor_->InitializeWithIv(key, iv);
|
||||
}
|
||||
|
||||
bool AesPatternCryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
iv_ = iv;
|
||||
return cryptor_->SetIv(iv);
|
||||
}
|
||||
|
||||
void AesPatternCryptor::UpdateIv() {
|
||||
cryptor_->UpdateIv();
|
||||
return SetIv(iv) && cryptor_->InitializeWithIv(key, iv);
|
||||
}
|
||||
|
||||
bool AesPatternCryptor::CryptInternal(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size) {
|
||||
if (constant_iv_flag_ == AesPatternCryptor::kUseConstantIv)
|
||||
CHECK(SetIv(iv_));
|
||||
|
||||
// |crypt_text_size| is always the same as |text_size| for pattern encryption.
|
||||
if (*crypt_text_size < text_size) {
|
||||
LOG(ERROR) << "Expecting output size of at least " << text_size
|
||||
|
@ -80,5 +67,9 @@ bool AesPatternCryptor::CryptInternal(const uint8_t* text,
|
|||
return true;
|
||||
}
|
||||
|
||||
void AesPatternCryptor::SetIvInternal() {
|
||||
CHECK(cryptor_->SetIv(iv()));
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -15,11 +15,6 @@ namespace media {
|
|||
/// Implements pattern-based encryption/decryption.
|
||||
class AesPatternCryptor : public AesCryptor {
|
||||
public:
|
||||
enum ConstantIvFlag {
|
||||
kUseConstantIv,
|
||||
kDontUseConstantIv,
|
||||
};
|
||||
|
||||
/// @param crypt_byte_block indicates number of encrypted blocks (16-byte) in
|
||||
/// pattern based encryption.
|
||||
/// @param skip_byte_block indicates number of unencrypted blocks (16-byte)
|
||||
|
@ -42,22 +37,18 @@ class AesPatternCryptor : public AesCryptor {
|
|||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
void UpdateIv() override;
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
private:
|
||||
bool CryptInternal(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size) override;
|
||||
void SetIvInternal() override;
|
||||
|
||||
private:
|
||||
const uint8_t crypt_byte_block_;
|
||||
const uint8_t skip_byte_block_;
|
||||
const ConstantIvFlag constant_iv_flag_;
|
||||
scoped_ptr<AesCryptor> cryptor_;
|
||||
std::vector<uint8_t> iv_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesPatternCryptor);
|
||||
};
|
||||
|
|
|
@ -24,16 +24,17 @@ namespace media {
|
|||
|
||||
class MockAesCryptor : public AesCryptor {
|
||||
public:
|
||||
MockAesCryptor() : AesCryptor(kDontUseConstantIv) {}
|
||||
|
||||
MOCK_METHOD2(InitializeWithIv,
|
||||
bool(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv));
|
||||
MOCK_METHOD1(SetIv, bool(const std::vector<uint8_t>& iv));
|
||||
MOCK_METHOD0(UpdateIv, void());
|
||||
MOCK_METHOD4(CryptInternal,
|
||||
bool(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size));
|
||||
MOCK_METHOD0(SetIvInternal, void());
|
||||
};
|
||||
|
||||
class AesPatternCryptorTest : public ::testing::Test {
|
||||
|
@ -42,7 +43,7 @@ class AesPatternCryptorTest : public ::testing::Test {
|
|||
: mock_cryptor_(new MockAesCryptor),
|
||||
pattern_cryptor_(kCryptByteBlock,
|
||||
kSkipByteBlock,
|
||||
AesPatternCryptor::kDontUseConstantIv,
|
||||
AesCryptor::kDontUseConstantIv,
|
||||
scoped_ptr<MockAesCryptor>(mock_cryptor_)) {}
|
||||
|
||||
protected:
|
||||
|
@ -55,11 +56,7 @@ TEST_F(AesPatternCryptorTest, InitializeWithIv) {
|
|||
std::vector<uint8_t> iv(8, 'i');
|
||||
EXPECT_CALL(*mock_cryptor_, InitializeWithIv(key, iv)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(pattern_cryptor_.InitializeWithIv(key, iv));
|
||||
}
|
||||
|
||||
TEST_F(AesPatternCryptorTest, UpdateIv) {
|
||||
EXPECT_CALL(*mock_cryptor_, UpdateIv());
|
||||
pattern_cryptor_.UpdateIv();
|
||||
EXPECT_EQ(iv, pattern_cryptor_.iv());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -152,7 +149,7 @@ TEST(AesPatternCryptorConstIvTest, UseConstantIv) {
|
|||
// SetIv will be called twice:
|
||||
// once by AesPatternCryptor::SetIv,
|
||||
// once by AesPatternCryptor::Crypt, to make sure the same iv is used.
|
||||
EXPECT_CALL(*mock_cryptor, SetIv(iv)).Times(2).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(*mock_cryptor, SetIvInternal()).Times(2);
|
||||
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
|
||||
|
||||
std::string crypt_text;
|
||||
|
@ -167,7 +164,7 @@ TEST(AesPatternCryptorConstIvTest, DontUseConstantIv) {
|
|||
|
||||
std::vector<uint8_t> iv(8, 'i');
|
||||
// SetIv will be called only once by AesPatternCryptor::SetIv.
|
||||
EXPECT_CALL(*mock_cryptor, SetIv(iv)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock_cryptor, SetIvInternal());
|
||||
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
|
||||
|
||||
std::string crypt_text;
|
||||
|
|
|
@ -46,22 +46,19 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
|
|||
aes_decryptor.reset(new AesCtrDecryptor);
|
||||
break;
|
||||
case FOURCC_cbc1:
|
||||
aes_decryptor.reset(new AesCbcDecryptor(kNoPadding, kChainAcrossCalls));
|
||||
aes_decryptor.reset(new AesCbcDecryptor(kNoPadding));
|
||||
break;
|
||||
case FOURCC_cens:
|
||||
aes_decryptor.reset(
|
||||
new AesPatternCryptor(decrypt_config->crypt_byte_block(),
|
||||
decrypt_config->skip_byte_block(),
|
||||
AesPatternCryptor::kDontUseConstantIv,
|
||||
aes_decryptor.reset(new AesPatternCryptor(
|
||||
decrypt_config->crypt_byte_block(),
|
||||
decrypt_config->skip_byte_block(), AesCryptor::kDontUseConstantIv,
|
||||
scoped_ptr<AesCryptor>(new AesCtrDecryptor)));
|
||||
break;
|
||||
case FOURCC_cbcs:
|
||||
aes_decryptor.reset(
|
||||
new AesPatternCryptor(decrypt_config->crypt_byte_block(),
|
||||
decrypt_config->skip_byte_block(),
|
||||
AesPatternCryptor::kUseConstantIv,
|
||||
scoped_ptr<AesCryptor>(new AesCbcDecryptor(
|
||||
kNoPadding, kChainAcrossCalls))));
|
||||
aes_decryptor.reset(new AesPatternCryptor(
|
||||
decrypt_config->crypt_byte_block(),
|
||||
decrypt_config->skip_byte_block(), AesCryptor::kUseConstantIv,
|
||||
scoped_ptr<AesCryptor>(new AesCbcDecryptor(kNoPadding))));
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unsupported protection scheme: "
|
||||
|
|
|
@ -41,7 +41,7 @@ AesRequestSigner* AesRequestSigner::CreateSigner(const std::string& signer_name,
|
|||
}
|
||||
|
||||
scoped_ptr<AesCbcEncryptor> encryptor(
|
||||
new AesCbcEncryptor(kPkcs5Padding, !kChainAcrossCalls));
|
||||
new AesCbcEncryptor(kPkcs5Padding, AesCryptor::kUseConstantIv));
|
||||
if (!encryptor->InitializeWithIv(aes_key, iv))
|
||||
return NULL;
|
||||
return new AesRequestSigner(signer_name, encryptor.Pass());
|
||||
|
|
|
@ -197,20 +197,17 @@ Status EncryptingFragmenter::CreateEncryptor() {
|
|||
encryptor.reset(new AesCtrEncryptor);
|
||||
break;
|
||||
case FOURCC_cbc1:
|
||||
encryptor.reset(new AesCbcEncryptor(kNoPadding, kChainAcrossCalls));
|
||||
encryptor.reset(new AesCbcEncryptor(kNoPadding));
|
||||
break;
|
||||
case FOURCC_cens:
|
||||
encryptor.reset(
|
||||
new AesPatternCryptor(crypt_byte_block(), skip_byte_block(),
|
||||
AesPatternCryptor::kDontUseConstantIv,
|
||||
encryptor.reset(new AesPatternCryptor(
|
||||
crypt_byte_block(), skip_byte_block(), AesCryptor::kDontUseConstantIv,
|
||||
scoped_ptr<AesCryptor>(new AesCtrEncryptor)));
|
||||
break;
|
||||
case FOURCC_cbcs:
|
||||
encryptor.reset(
|
||||
new AesPatternCryptor(crypt_byte_block(), skip_byte_block(),
|
||||
AesPatternCryptor::kUseConstantIv,
|
||||
scoped_ptr<AesCryptor>(new AesCbcEncryptor(
|
||||
kNoPadding, kChainAcrossCalls))));
|
||||
encryptor.reset(new AesPatternCryptor(
|
||||
crypt_byte_block(), skip_byte_block(), AesCryptor::kUseConstantIv,
|
||||
scoped_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
|
||||
break;
|
||||
default:
|
||||
return Status(error::MUXER_FAILURE, "Unsupported protection scheme.");
|
||||
|
|
|
@ -1114,7 +1114,7 @@ bool WvmMediaParser::ProcessEcm() {
|
|||
encryption_key.key.begin(),
|
||||
encryption_key.key.begin() + kAssetKeySizeBytes);
|
||||
std::vector<uint8_t> iv(kInitializationVectorSizeBytes);
|
||||
AesCbcDecryptor asset_decryptor(kCtsPadding, !kChainAcrossCalls);
|
||||
AesCbcDecryptor asset_decryptor(kCtsPadding, AesCryptor::kUseConstantIv);
|
||||
if (!asset_decryptor.InitializeWithIv(asset_key, iv)) {
|
||||
LOG(ERROR) << "Failed to initialize asset_decryptor.";
|
||||
return false;
|
||||
|
@ -1131,7 +1131,7 @@ bool WvmMediaParser::ProcessEcm() {
|
|||
content_key_buffer.begin() + 4,
|
||||
content_key_buffer.begin() + 20);
|
||||
scoped_ptr<AesCbcDecryptor> content_decryptor(
|
||||
new AesCbcDecryptor(kCtsPadding, !kChainAcrossCalls));
|
||||
new AesCbcDecryptor(kCtsPadding, AesCryptor::kUseConstantIv));
|
||||
if (!content_decryptor->InitializeWithIv(decrypted_content_key_vec, iv)) {
|
||||
LOG(ERROR) << "Failed to initialize content decryptor.";
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue