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")) {
|
"--enable_fixed_key_encryption")) {
|
||||||
success = false;
|
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.
|
// --pssh is associated with --enable_fix_key_encryption.
|
||||||
if (!ValidateFlag("pssh",
|
if (!ValidateFlag("pssh",
|
||||||
|
|
|
@ -384,12 +384,6 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
const FourCC protection_scheme = GetProtectionScheme(FLAGS_protection_scheme);
|
const FourCC protection_scheme = GetProtectionScheme(FLAGS_protection_scheme);
|
||||||
if (protection_scheme == FOURCC_NULL)
|
if (protection_scheme == FOURCC_NULL)
|
||||||
return false;
|
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())
|
if (!AssignFlagsFromProfile())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -61,7 +61,7 @@ DEFINE_string(protection_scheme,
|
||||||
"protection schemes 'cens' or 'cbcs'. Note that if a "
|
"protection schemes 'cens' or 'cbcs'. Note that if a "
|
||||||
"pattern-based protection scheme only applies to video stream; "
|
"pattern-based protection scheme only applies to video stream; "
|
||||||
"audio stream will be encrypted using the corresponding "
|
"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'.");
|
"'cbc1' for 'cbcs'.");
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
#include "packager/media/base/aes_cryptor.h"
|
#include "packager/media/base/aes_cryptor.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
@ -13,10 +16,24 @@
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/base/stl_util.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 edash_packager {
|
||||||
namespace media {
|
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() {}
|
AesCryptor::~AesCryptor() {}
|
||||||
|
|
||||||
bool AesCryptor::Crypt(const std::vector<uint8_t>& text,
|
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();
|
const size_t text_size = text.size();
|
||||||
crypt_text->resize(text_size + NumPaddingBytes(text_size));
|
crypt_text->resize(text_size + NumPaddingBytes(text_size));
|
||||||
size_t crypt_text_size = crypt_text->size();
|
size_t crypt_text_size = crypt_text->size();
|
||||||
if (!CryptInternal(text.data(), text_size, crypt_text->data(),
|
if (!Crypt(text.data(), text_size, crypt_text->data(), &crypt_text_size)) {
|
||||||
&crypt_text_size)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
DCHECK_LE(crypt_text_size, crypt_text->size());
|
DCHECK_LE(crypt_text_size, crypt_text->size());
|
||||||
|
@ -41,18 +57,53 @@ bool AesCryptor::Crypt(const std::string& text, std::string* crypt_text) {
|
||||||
const size_t text_size = text.size();
|
const size_t text_size = text.size();
|
||||||
crypt_text->resize(text_size + NumPaddingBytes(text_size));
|
crypt_text->resize(text_size + NumPaddingBytes(text_size));
|
||||||
size_t crypt_text_size = crypt_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)),
|
reinterpret_cast<uint8_t*>(string_as_array(crypt_text)),
|
||||||
&crypt_text_size))
|
&crypt_text_size))
|
||||||
return false;
|
return false;
|
||||||
DCHECK_LE(crypt_text_size, crypt_text->size());
|
DCHECK_LE(crypt_text_size, crypt_text->size());
|
||||||
crypt_text->resize(crypt_text_size);
|
crypt_text->resize(crypt_text_size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AesCryptor::NumPaddingBytes(size_t size) const {
|
bool AesCryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||||
// No padding by default.
|
if (!IsIvSizeValid(iv.size())) {
|
||||||
return 0;
|
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,
|
bool AesCryptor::GenerateRandomIv(FourCC protection_scheme,
|
||||||
|
@ -74,6 +125,11 @@ bool AesCryptor::GenerateRandomIv(FourCC protection_scheme,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t AesCryptor::NumPaddingBytes(size_t size) const {
|
||||||
|
// No padding by default.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,18 @@ namespace media {
|
||||||
// implementations.
|
// implementations.
|
||||||
class AesCryptor {
|
class AesCryptor {
|
||||||
public:
|
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();
|
virtual ~AesCryptor();
|
||||||
|
|
||||||
/// Initialize the cryptor with specified key and IV.
|
/// 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.
|
/// @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) {
|
bool Crypt(const uint8_t* text, size_t text_size, uint8_t* crypt_text) {
|
||||||
size_t crypt_text_size = text_size;
|
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.
|
/// Set IV.
|
||||||
/// @return true if successful, false if the input is invalid.
|
/// @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
|
/// Update IV for next sample. As recommended in ISO/IEC 23001-7: IV need to
|
||||||
/// be updated per sample for CENC.
|
/// be updated per sample for CENC.
|
||||||
/// This is used by encryptors only.
|
/// This is used by encryptors only. It is a NOP if using kUseConstantIv.
|
||||||
virtual void UpdateIv() = 0;
|
void UpdateIv();
|
||||||
|
|
||||||
/// @return The current iv.
|
/// @return The current iv.
|
||||||
const std::vector<uint8_t>& iv() const { return iv_; }
|
const std::vector<uint8_t>& iv() const { return iv_; }
|
||||||
|
@ -67,7 +88,6 @@ class AesCryptor {
|
||||||
std::vector<uint8_t>* iv);
|
std::vector<uint8_t>* iv);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_iv(const std::vector<uint8_t>& iv) { iv_ = iv; }
|
|
||||||
const AES_KEY* aes_key() const { return aes_key_.get(); }
|
const AES_KEY* aes_key() const { return aes_key_.get(); }
|
||||||
AES_KEY* mutable_aes_key() { return aes_key_.get(); }
|
AES_KEY* mutable_aes_key() { return aes_key_.get(); }
|
||||||
|
|
||||||
|
@ -87,16 +107,27 @@ class AesCryptor {
|
||||||
uint8_t* crypt_text,
|
uint8_t* crypt_text,
|
||||||
size_t* crypt_text_size) = 0;
|
size_t* crypt_text_size) = 0;
|
||||||
|
|
||||||
|
// Internal implementation of SetIv, which setup internal iv.
|
||||||
|
virtual void SetIvInternal() = 0;
|
||||||
|
|
||||||
// |size| specifies the input text size.
|
// |size| specifies the input text size.
|
||||||
// Return the number of padding bytes needed.
|
// Return the number of padding bytes needed.
|
||||||
// Note: No paddings should be needed except for pkcs5-cbc encryptor.
|
// Note: No paddings should be needed except for pkcs5-cbc encryptor.
|
||||||
virtual size_t NumPaddingBytes(size_t size) const;
|
virtual size_t NumPaddingBytes(size_t size) const;
|
||||||
|
|
||||||
// Initialization vector, with size 8 or 16.
|
|
||||||
std::vector<uint8_t> iv_;
|
|
||||||
// Openssl AES_KEY.
|
// Openssl AES_KEY.
|
||||||
scoped_ptr<AES_KEY> 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);
|
DISALLOW_COPY_AND_ASSIGN(AesCryptor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,20 @@ TEST_F(AesCtrEncryptorTest, 128BitIVBoundaryCaseEncryption) {
|
||||||
EXPECT_EQ(encrypted, encrypted_verify);
|
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) {
|
TEST_F(AesCtrEncryptorTest, GenerateRandomIv) {
|
||||||
const uint8_t kCencIvSize = 8;
|
const uint8_t kCencIvSize = 8;
|
||||||
std::vector<uint8_t> iv;
|
std::vector<uint8_t> iv;
|
||||||
|
@ -297,8 +311,10 @@ INSTANTIATE_TEST_CASE_P(IvTestCases,
|
||||||
class AesCbcTest : public ::testing::Test {
|
class AesCbcTest : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
AesCbcTest()
|
AesCbcTest()
|
||||||
: encryptor_(new AesCbcEncryptor(kPkcs5Padding, !kChainAcrossCalls)),
|
: encryptor_(
|
||||||
decryptor_(new AesCbcDecryptor(kPkcs5Padding, !kChainAcrossCalls)),
|
new AesCbcEncryptor(kPkcs5Padding, AesCryptor::kUseConstantIv)),
|
||||||
|
decryptor_(
|
||||||
|
new AesCbcDecryptor(kPkcs5Padding, AesCryptor::kUseConstantIv)),
|
||||||
key_(kAesKey, kAesKey + arraysize(kAesKey)),
|
key_(kAesKey, kAesKey + arraysize(kAesKey)),
|
||||||
iv_(kAesIv, kAesIv + arraysize(kAesIv)) {}
|
iv_(kAesIv, kAesIv + arraysize(kAesIv)) {}
|
||||||
|
|
||||||
|
@ -450,25 +466,21 @@ TEST_F(AesCbcTest, NoPaddingNoChainAcrossCalls) {
|
||||||
std::vector<uint8_t> ciphertext(kCiphertext,
|
std::vector<uint8_t> ciphertext(kCiphertext,
|
||||||
kCiphertext + arraysize(kCiphertext));
|
kCiphertext + arraysize(kCiphertext));
|
||||||
|
|
||||||
AesCbcEncryptor encryptor(kNoPadding, !kChainAcrossCalls);
|
AesCbcEncryptor encryptor(kNoPadding, AesCryptor::kUseConstantIv);
|
||||||
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
std::vector<uint8_t> encrypted;
|
std::vector<uint8_t> encrypted;
|
||||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||||
EXPECT_EQ(ciphertext, encrypted);
|
EXPECT_EQ(ciphertext, encrypted);
|
||||||
// Iv should not have been updated.
|
|
||||||
EXPECT_EQ(iv_, encryptor.iv());
|
|
||||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||||
EXPECT_EQ(ciphertext, encrypted);
|
EXPECT_EQ(ciphertext, encrypted);
|
||||||
|
|
||||||
AesCbcDecryptor decryptor(kNoPadding, !kChainAcrossCalls);
|
AesCbcDecryptor decryptor(kNoPadding, AesCryptor::kUseConstantIv);
|
||||||
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
std::vector<uint8_t> decrypted;
|
std::vector<uint8_t> decrypted;
|
||||||
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
||||||
EXPECT_EQ(plaintext, decrypted);
|
EXPECT_EQ(plaintext, decrypted);
|
||||||
// Iv should not have been updated.
|
|
||||||
EXPECT_EQ(iv_, encryptor.iv());
|
|
||||||
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
||||||
EXPECT_EQ(plaintext, decrypted);
|
EXPECT_EQ(plaintext, decrypted);
|
||||||
}
|
}
|
||||||
|
@ -494,26 +506,23 @@ TEST_F(AesCbcTest, NoPaddingChainAcrossCalls) {
|
||||||
std::vector<uint8_t> ciphertext2(kCiphertext2,
|
std::vector<uint8_t> ciphertext2(kCiphertext2,
|
||||||
kCiphertext2 + arraysize(kCiphertext2));
|
kCiphertext2 + arraysize(kCiphertext2));
|
||||||
|
|
||||||
AesCbcEncryptor encryptor(kNoPadding, kChainAcrossCalls);
|
AesCbcEncryptor encryptor(kNoPadding, AesCryptor::kDontUseConstantIv);
|
||||||
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
std::vector<uint8_t> encrypted;
|
std::vector<uint8_t> encrypted;
|
||||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||||
EXPECT_EQ(ciphertext, encrypted);
|
EXPECT_EQ(ciphertext, encrypted);
|
||||||
// Iv should have been updated.
|
|
||||||
EXPECT_NE(iv_, encryptor.iv());
|
|
||||||
// If run encrypt again, the result will be different.
|
// If run encrypt again, the result will be different.
|
||||||
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
|
||||||
|
EXPECT_NE(ciphertext, ciphertext2);
|
||||||
EXPECT_EQ(ciphertext2, encrypted);
|
EXPECT_EQ(ciphertext2, encrypted);
|
||||||
|
|
||||||
AesCbcDecryptor decryptor(kNoPadding, kChainAcrossCalls);
|
AesCbcDecryptor decryptor(kNoPadding, AesCryptor::kDontUseConstantIv);
|
||||||
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
std::vector<uint8_t> decrypted;
|
std::vector<uint8_t> decrypted;
|
||||||
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
|
||||||
EXPECT_EQ(plaintext, 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.
|
// If run decrypt on ciphertext2 now, it will return the original plaintext.
|
||||||
ASSERT_TRUE(decryptor.Crypt(ciphertext2, &decrypted));
|
ASSERT_TRUE(decryptor.Crypt(ciphertext2, &decrypted));
|
||||||
EXPECT_EQ(plaintext, decrypted);
|
EXPECT_EQ(plaintext, decrypted);
|
||||||
|
@ -524,9 +533,11 @@ TEST_F(AesCbcTest, UnsupportedKeySize) {
|
||||||
EXPECT_FALSE(decryptor_->InitializeWithIv(std::vector<uint8_t>(15, 0), iv_));
|
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(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) {
|
TEST_F(AesCbcTest, Pkcs5CipherTextNotMultipleOfBlockSize) {
|
||||||
|
@ -584,10 +595,10 @@ class AesCbcCryptorVerificationTest
|
||||||
public ::testing::WithParamInterface<CbcTestCase> {};
|
public ::testing::WithParamInterface<CbcTestCase> {};
|
||||||
|
|
||||||
TEST_P(AesCbcCryptorVerificationTest, EncryptDecryptTest) {
|
TEST_P(AesCbcCryptorVerificationTest, EncryptDecryptTest) {
|
||||||
encryptor_.reset(
|
encryptor_.reset(new AesCbcEncryptor(GetParam().padding_scheme,
|
||||||
new AesCbcEncryptor(GetParam().padding_scheme, !kChainAcrossCalls));
|
AesCryptor::kUseConstantIv));
|
||||||
decryptor_.reset(
|
decryptor_.reset(new AesCbcDecryptor(GetParam().padding_scheme,
|
||||||
new AesCbcDecryptor(GetParam().padding_scheme, !kChainAcrossCalls));
|
AesCryptor::kUseConstantIv));
|
||||||
|
|
||||||
std::vector<uint8_t> plaintext;
|
std::vector<uint8_t> plaintext;
|
||||||
std::string plaintext_hex(GetParam().plaintext_hex);
|
std::string plaintext_hex(GetParam().plaintext_hex);
|
||||||
|
|
|
@ -22,13 +22,16 @@ bool IsKeySizeValidForAes(size_t key_size) {
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme)
|
||||||
|
: AesCbcDecryptor(padding_scheme, kDontUseConstantIv) {}
|
||||||
|
|
||||||
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
|
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
|
||||||
bool chain_across_calls)
|
ConstantIvFlag constant_iv_flag)
|
||||||
: padding_scheme_(padding_scheme),
|
: AesCryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
|
||||||
chain_across_calls_(chain_across_calls) {
|
|
||||||
if (padding_scheme_ != kNoPadding) {
|
if (padding_scheme_ != kNoPadding) {
|
||||||
CHECK(!chain_across_calls) << "cipher block chain across calls only makes "
|
CHECK_EQ(constant_iv_flag, kUseConstantIv)
|
||||||
"sense if the padding_scheme is kNoPadding.";
|
<< "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);
|
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,
|
bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
||||||
size_t ciphertext_size,
|
size_t ciphertext_size,
|
||||||
uint8_t* plaintext,
|
uint8_t* plaintext,
|
||||||
|
@ -82,14 +75,11 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
||||||
}
|
}
|
||||||
DCHECK(plaintext);
|
DCHECK(plaintext);
|
||||||
|
|
||||||
std::vector<uint8_t> local_iv(iv());
|
|
||||||
const size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
|
const size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
|
||||||
const size_t cbc_size = ciphertext_size - residual_block_size;
|
const size_t cbc_size = ciphertext_size - residual_block_size;
|
||||||
if (residual_block_size == 0) {
|
if (residual_block_size == 0) {
|
||||||
AES_cbc_encrypt(ciphertext, plaintext, ciphertext_size, aes_key(),
|
AES_cbc_encrypt(ciphertext, plaintext, ciphertext_size, aes_key(),
|
||||||
local_iv.data(), AES_DECRYPT);
|
internal_iv_.data(), AES_DECRYPT);
|
||||||
if (chain_across_calls_)
|
|
||||||
set_iv(local_iv);
|
|
||||||
if (padding_scheme_ != kPkcs5Padding)
|
if (padding_scheme_ != kPkcs5Padding)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -103,10 +93,8 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
||||||
*plaintext_size -= num_padding_bytes;
|
*plaintext_size -= num_padding_bytes;
|
||||||
return true;
|
return true;
|
||||||
} else if (padding_scheme_ == kNoPadding) {
|
} else if (padding_scheme_ == kNoPadding) {
|
||||||
AES_cbc_encrypt(ciphertext, plaintext, cbc_size, aes_key(), local_iv.data(),
|
AES_cbc_encrypt(ciphertext, plaintext, cbc_size, aes_key(),
|
||||||
AES_DECRYPT);
|
internal_iv_.data(), AES_DECRYPT);
|
||||||
if (chain_across_calls_)
|
|
||||||
set_iv(local_iv);
|
|
||||||
|
|
||||||
// The residual block is not encrypted.
|
// The residual block is not encrypted.
|
||||||
memcpy(plaintext + cbc_size, ciphertext + cbc_size, residual_block_size);
|
memcpy(plaintext + cbc_size, ciphertext + cbc_size, residual_block_size);
|
||||||
|
@ -117,7 +105,6 @@ bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK(!chain_across_calls_);
|
|
||||||
DCHECK_EQ(padding_scheme_, kCtsPadding);
|
DCHECK_EQ(padding_scheme_, kCtsPadding);
|
||||||
if (ciphertext_size < AES_BLOCK_SIZE) {
|
if (ciphertext_size < AES_BLOCK_SIZE) {
|
||||||
// Don't have a full block, leave unencrypted.
|
// 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.
|
// AES-CBC decrypt everything up to the next-to-last full block.
|
||||||
if (cbc_size > AES_BLOCK_SIZE) {
|
if (cbc_size > AES_BLOCK_SIZE) {
|
||||||
AES_cbc_encrypt(ciphertext, plaintext, cbc_size - AES_BLOCK_SIZE, aes_key(),
|
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 =
|
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.
|
// Decrypt the next-to-last full block.
|
||||||
AES_cbc_encrypt(next_to_last_plaintext_block, next_to_last_plaintext_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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AesCbcDecryptor::SetIvInternal() {
|
||||||
|
internal_iv_ = iv();
|
||||||
|
internal_iv_.resize(AES_BLOCK_SIZE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -24,22 +24,28 @@ using AesCtrDecryptor = AesCtrEncryptor;
|
||||||
/// Class which implements AES-CBC (Cipher block chaining) decryption.
|
/// Class which implements AES-CBC (Cipher block chaining) decryption.
|
||||||
class AesCbcDecryptor : public AesCryptor {
|
class AesCbcDecryptor : public AesCryptor {
|
||||||
public:
|
public:
|
||||||
|
/// Creates a AesCbcDecryptor with continous cipher block chain across Crypt
|
||||||
|
/// calls.
|
||||||
/// @param padding_scheme indicates the padding scheme used. Currently
|
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||||
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
||||||
/// @param chain_across_calls indicates whether there is a continuous cipher
|
explicit AesCbcDecryptor(CbcPaddingScheme padding_scheme);
|
||||||
/// block chain across calls for Decrypt function. If it is false, iv
|
|
||||||
/// is not updated across Decrypt function calls.
|
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||||
AesCbcDecryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls);
|
/// 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;
|
~AesCbcDecryptor() override;
|
||||||
|
|
||||||
/// @name AesCryptor implementation overrides.
|
/// @name AesCryptor implementation overrides.
|
||||||
/// @{
|
/// @{
|
||||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||||
const std::vector<uint8_t>& iv) override;
|
const std::vector<uint8_t>& iv) override;
|
||||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
|
||||||
void UpdateIv() override {
|
|
||||||
// Nop for decryptor.
|
|
||||||
}
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -47,9 +53,11 @@ class AesCbcDecryptor : public AesCryptor {
|
||||||
size_t ciphertext_size,
|
size_t ciphertext_size,
|
||||||
uint8_t* plaintext,
|
uint8_t* plaintext,
|
||||||
size_t* plaintext_size) override;
|
size_t* plaintext_size) override;
|
||||||
|
void SetIvInternal() override;
|
||||||
|
|
||||||
const CbcPaddingScheme padding_scheme_;
|
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);
|
DISALLOW_COPY_AND_ASSIGN(AesCbcDecryptor);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,16 +15,13 @@ namespace {
|
||||||
// Increment an 8-byte counter by 1. Return true if overflowed.
|
// Increment an 8-byte counter by 1. Return true if overflowed.
|
||||||
bool Increment64(uint8_t* counter) {
|
bool Increment64(uint8_t* counter) {
|
||||||
DCHECK(counter);
|
DCHECK(counter);
|
||||||
for (int i = 7; i >= 0; --i)
|
for (int i = 7; i >= 0; --i) {
|
||||||
if (++counter[i] != 0)
|
if (++counter[i] != 0)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
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.
|
// AES defines three key sizes: 128, 192 and 256 bits.
|
||||||
bool IsKeySizeValidForAes(size_t key_size) {
|
bool IsKeySizeValidForAes(size_t key_size) {
|
||||||
return key_size == 16 || key_size == 24 || key_size == 32;
|
return key_size == 16 || key_size == 24 || key_size == 32;
|
||||||
|
@ -35,7 +32,8 @@ bool IsKeySizeValidForAes(size_t key_size) {
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
AesEncryptor::AesEncryptor() {}
|
AesEncryptor::AesEncryptor(ConstantIvFlag constant_iv_flag)
|
||||||
|
: AesCryptor(constant_iv_flag) {}
|
||||||
AesEncryptor::~AesEncryptor() {}
|
AesEncryptor::~AesEncryptor() {}
|
||||||
|
|
||||||
bool AesEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
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);
|
return SetIv(iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't support constant iv for counter mode, as we don't have a use case
|
||||||
|
// for that.
|
||||||
AesCtrEncryptor::AesCtrEncryptor()
|
AesCtrEncryptor::AesCtrEncryptor()
|
||||||
: block_offset_(0),
|
: AesEncryptor(kDontUseConstantIv),
|
||||||
encrypted_counter_(AES_BLOCK_SIZE, 0),
|
block_offset_(0),
|
||||||
counter_overflow_(false) {}
|
encrypted_counter_(AES_BLOCK_SIZE, 0) {}
|
||||||
|
|
||||||
AesCtrEncryptor::~AesCtrEncryptor() {}
|
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,
|
bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||||
size_t plaintext_size,
|
size_t plaintext_size,
|
||||||
|
@ -119,13 +77,12 @@ bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||||
for (size_t i = 0; i < plaintext_size; ++i) {
|
for (size_t i = 0; i < plaintext_size; ++i) {
|
||||||
if (block_offset_ == 0) {
|
if (block_offset_ == 0) {
|
||||||
AES_encrypt(&counter_[0], &encrypted_counter_[0], aes_key());
|
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
|
// 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
|
// simple 64 bit unsigned integer that is incremented by one for each
|
||||||
// subsequent block of sample data processed and is kept in network byte
|
// subsequent block of sample data processed and is kept in network byte
|
||||||
// order.
|
// order.
|
||||||
if (Increment64(&counter_[8]))
|
Increment64(&counter_[8]);
|
||||||
counter_overflow_ = true;
|
|
||||||
}
|
}
|
||||||
ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
|
ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
|
||||||
block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
|
block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
|
||||||
|
@ -133,37 +90,27 @@ bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||||
return true;
|
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,
|
AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme,
|
||||||
bool chain_across_calls)
|
ConstantIvFlag constant_iv_flag)
|
||||||
: padding_scheme_(padding_scheme),
|
: AesEncryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
|
||||||
chain_across_calls_(chain_across_calls) {
|
|
||||||
if (padding_scheme_ != kNoPadding) {
|
if (padding_scheme_ != kNoPadding) {
|
||||||
CHECK(!chain_across_calls) << "cipher block chain across calls only makes "
|
CHECK_EQ(constant_iv_flag, kUseConstantIv)
|
||||||
"sense if the padding_scheme is kNoPadding.";
|
<< "non-constant iv (cipher block chain across calls) only makes sense "
|
||||||
|
"if the padding_scheme is kNoPadding.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AesCbcEncryptor::~AesCbcEncryptor() {}
|
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,
|
bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||||
size_t plaintext_size,
|
size_t plaintext_size,
|
||||||
uint8_t* ciphertext,
|
uint8_t* ciphertext,
|
||||||
|
@ -182,22 +129,18 @@ bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||||
|
|
||||||
// Encrypt everything but the residual block using CBC.
|
// Encrypt everything but the residual block using CBC.
|
||||||
const size_t cbc_size = plaintext_size - residual_block_size;
|
const size_t cbc_size = plaintext_size - residual_block_size;
|
||||||
std::vector<uint8_t> local_iv(iv());
|
|
||||||
if (cbc_size != 0) {
|
if (cbc_size != 0) {
|
||||||
AES_cbc_encrypt(plaintext, ciphertext, cbc_size, aes_key(), local_iv.data(),
|
AES_cbc_encrypt(plaintext, ciphertext, cbc_size, aes_key(),
|
||||||
AES_ENCRYPT);
|
internal_iv_.data(), AES_ENCRYPT);
|
||||||
} else if (padding_scheme_ == kCtsPadding) {
|
} else if (padding_scheme_ == kCtsPadding) {
|
||||||
// Don't have a full block, leave unencrypted.
|
// Don't have a full block, leave unencrypted.
|
||||||
memcpy(ciphertext, plaintext, plaintext_size);
|
memcpy(ciphertext, plaintext, plaintext_size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (residual_block_size == 0 && padding_scheme_ != kPkcs5Padding) {
|
if (residual_block_size == 0 && padding_scheme_ != kPkcs5Padding) {
|
||||||
if (chain_across_calls_)
|
|
||||||
set_iv(local_iv);
|
|
||||||
// No residual block. No need to do padding.
|
// No residual block. No need to do padding.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
DCHECK(!chain_across_calls_);
|
|
||||||
|
|
||||||
if (padding_scheme_ == kNoPadding) {
|
if (padding_scheme_ == kNoPadding) {
|
||||||
// The residual block is left unencrypted.
|
// The residual block is left unencrypted.
|
||||||
|
@ -216,7 +159,8 @@ bool AesCbcEncryptor::CryptInternal(const uint8_t* plaintext,
|
||||||
// Pad residue block with PKCS5 padding.
|
// Pad residue block with PKCS5 padding.
|
||||||
residual_block.resize(AES_BLOCK_SIZE, static_cast<char>(num_padding_bytes));
|
residual_block.resize(AES_BLOCK_SIZE, static_cast<char>(num_padding_bytes));
|
||||||
AES_cbc_encrypt(residual_block.data(), residual_ciphertext_block,
|
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 {
|
} else {
|
||||||
DCHECK_EQ(num_padding_bytes, 0u);
|
DCHECK_EQ(num_padding_bytes, 0u);
|
||||||
DCHECK_EQ(padding_scheme_, kCtsPadding);
|
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.
|
// Zero-pad the residual block and encrypt using CBC.
|
||||||
residual_block.resize(AES_BLOCK_SIZE, 0);
|
residual_block.resize(AES_BLOCK_SIZE, 0);
|
||||||
AES_cbc_encrypt(residual_block.data(), residual_block.data(),
|
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
|
// Replace the last full block with the zero-padded, encrypted residual
|
||||||
// block, and replace the residual block with the equivalent portion of the
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AesCbcEncryptor::SetIvInternal() {
|
||||||
|
internal_iv_ = iv();
|
||||||
|
internal_iv_.resize(AES_BLOCK_SIZE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
size_t AesCbcEncryptor::NumPaddingBytes(size_t size) const {
|
size_t AesCbcEncryptor::NumPaddingBytes(size_t size) const {
|
||||||
return (padding_scheme_ == kPkcs5Padding)
|
return (padding_scheme_ == kPkcs5Padding)
|
||||||
? (AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE))
|
? (AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE))
|
||||||
|
|
|
@ -21,7 +21,13 @@ namespace media {
|
||||||
|
|
||||||
class AesEncryptor : public AesCryptor {
|
class AesEncryptor : public AesCryptor {
|
||||||
public:
|
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;
|
~AesEncryptor() override;
|
||||||
|
|
||||||
/// Initialize the encryptor with specified key and IV.
|
/// Initialize the encryptor with specified key and IV.
|
||||||
|
@ -39,17 +45,6 @@ class AesCtrEncryptor : public AesEncryptor {
|
||||||
AesCtrEncryptor();
|
AesCtrEncryptor();
|
||||||
~AesCtrEncryptor() override;
|
~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_; }
|
uint32_t block_offset() const { return block_offset_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -57,6 +52,7 @@ class AesCtrEncryptor : public AesEncryptor {
|
||||||
size_t plaintext_size,
|
size_t plaintext_size,
|
||||||
uint8_t* ciphertext,
|
uint8_t* ciphertext,
|
||||||
size_t* ciphertext_size) override;
|
size_t* ciphertext_size) override;
|
||||||
|
void SetIvInternal() override;
|
||||||
|
|
||||||
// Current block offset.
|
// Current block offset.
|
||||||
uint32_t block_offset_;
|
uint32_t block_offset_;
|
||||||
|
@ -64,8 +60,6 @@ class AesCtrEncryptor : public AesEncryptor {
|
||||||
std::vector<uint8_t> counter_;
|
std::vector<uint8_t> counter_;
|
||||||
// Encrypted counter.
|
// Encrypted counter.
|
||||||
std::vector<uint8_t> encrypted_counter_;
|
std::vector<uint8_t> encrypted_counter_;
|
||||||
// Keep track of whether the counter has overflowed.
|
|
||||||
bool counter_overflow_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AesCtrEncryptor);
|
DISALLOW_COPY_AND_ASSIGN(AesCtrEncryptor);
|
||||||
};
|
};
|
||||||
|
@ -80,35 +74,38 @@ enum CbcPaddingScheme {
|
||||||
kCtsPadding,
|
kCtsPadding,
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool kChainAcrossCalls = true;
|
|
||||||
|
|
||||||
// Class which implements AES-CBC (Cipher block chaining) encryption.
|
// Class which implements AES-CBC (Cipher block chaining) encryption.
|
||||||
class AesCbcEncryptor : public AesEncryptor {
|
class AesCbcEncryptor : public AesEncryptor {
|
||||||
public:
|
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
|
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||||
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
/// supported schemes: kNoPadding, kPkcs5Padding, kCtsPadding.
|
||||||
/// @param chain_across_calls indicates whether there is a continuous cipher
|
explicit AesCbcEncryptor(CbcPaddingScheme padding_scheme);
|
||||||
/// block chain across calls for Encrypt function. If it is false, iv
|
|
||||||
/// is not updated across Encrypt function calls.
|
/// @param padding_scheme indicates the padding scheme used. Currently
|
||||||
AesCbcEncryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls);
|
/// 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;
|
~AesCbcEncryptor() override;
|
||||||
|
|
||||||
/// @name AesCryptor implementation overrides.
|
|
||||||
/// @{
|
|
||||||
void UpdateIv() override;
|
|
||||||
|
|
||||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
|
||||||
/// @}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CryptInternal(const uint8_t* plaintext,
|
bool CryptInternal(const uint8_t* plaintext,
|
||||||
size_t plaintext_size,
|
size_t plaintext_size,
|
||||||
uint8_t* ciphertext,
|
uint8_t* ciphertext,
|
||||||
size_t* ciphertext_size) override;
|
size_t* ciphertext_size) override;
|
||||||
|
void SetIvInternal() override;
|
||||||
size_t NumPaddingBytes(size_t size) const override;
|
size_t NumPaddingBytes(size_t size) const override;
|
||||||
|
|
||||||
const CbcPaddingScheme padding_scheme_;
|
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);
|
DISALLOW_COPY_AND_ASSIGN(AesCbcEncryptor);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,9 +17,9 @@ AesPatternCryptor::AesPatternCryptor(uint8_t crypt_byte_block,
|
||||||
uint8_t skip_byte_block,
|
uint8_t skip_byte_block,
|
||||||
ConstantIvFlag constant_iv_flag,
|
ConstantIvFlag constant_iv_flag,
|
||||||
scoped_ptr<AesCryptor> cryptor)
|
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),
|
skip_byte_block_(skip_byte_block),
|
||||||
constant_iv_flag_(constant_iv_flag),
|
|
||||||
cryptor_(cryptor.Pass()) {
|
cryptor_(cryptor.Pass()) {
|
||||||
DCHECK(cryptor_);
|
DCHECK(cryptor_);
|
||||||
}
|
}
|
||||||
|
@ -28,26 +28,13 @@ AesPatternCryptor::~AesPatternCryptor() {}
|
||||||
|
|
||||||
bool AesPatternCryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
bool AesPatternCryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||||
const std::vector<uint8_t>& iv) {
|
const std::vector<uint8_t>& iv) {
|
||||||
iv_ = iv;
|
return SetIv(iv) && cryptor_->InitializeWithIv(key, 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AesPatternCryptor::CryptInternal(const uint8_t* text,
|
bool AesPatternCryptor::CryptInternal(const uint8_t* text,
|
||||||
size_t text_size,
|
size_t text_size,
|
||||||
uint8_t* crypt_text,
|
uint8_t* crypt_text,
|
||||||
size_t* crypt_text_size) {
|
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.
|
// |crypt_text_size| is always the same as |text_size| for pattern encryption.
|
||||||
if (*crypt_text_size < text_size) {
|
if (*crypt_text_size < text_size) {
|
||||||
LOG(ERROR) << "Expecting output size of at least " << 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AesPatternCryptor::SetIvInternal() {
|
||||||
|
CHECK(cryptor_->SetIv(iv()));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -15,11 +15,6 @@ namespace media {
|
||||||
/// Implements pattern-based encryption/decryption.
|
/// Implements pattern-based encryption/decryption.
|
||||||
class AesPatternCryptor : public AesCryptor {
|
class AesPatternCryptor : public AesCryptor {
|
||||||
public:
|
public:
|
||||||
enum ConstantIvFlag {
|
|
||||||
kUseConstantIv,
|
|
||||||
kDontUseConstantIv,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @param crypt_byte_block indicates number of encrypted blocks (16-byte) in
|
/// @param crypt_byte_block indicates number of encrypted blocks (16-byte) in
|
||||||
/// pattern based encryption.
|
/// pattern based encryption.
|
||||||
/// @param skip_byte_block indicates number of unencrypted blocks (16-byte)
|
/// @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,
|
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||||
const std::vector<uint8_t>& iv) override;
|
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,
|
bool CryptInternal(const uint8_t* text,
|
||||||
size_t text_size,
|
size_t text_size,
|
||||||
uint8_t* crypt_text,
|
uint8_t* crypt_text,
|
||||||
size_t* crypt_text_size) override;
|
size_t* crypt_text_size) override;
|
||||||
|
void SetIvInternal() override;
|
||||||
|
|
||||||
private:
|
|
||||||
const uint8_t crypt_byte_block_;
|
const uint8_t crypt_byte_block_;
|
||||||
const uint8_t skip_byte_block_;
|
const uint8_t skip_byte_block_;
|
||||||
const ConstantIvFlag constant_iv_flag_;
|
|
||||||
scoped_ptr<AesCryptor> cryptor_;
|
scoped_ptr<AesCryptor> cryptor_;
|
||||||
std::vector<uint8_t> iv_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AesPatternCryptor);
|
DISALLOW_COPY_AND_ASSIGN(AesPatternCryptor);
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,16 +24,17 @@ namespace media {
|
||||||
|
|
||||||
class MockAesCryptor : public AesCryptor {
|
class MockAesCryptor : public AesCryptor {
|
||||||
public:
|
public:
|
||||||
|
MockAesCryptor() : AesCryptor(kDontUseConstantIv) {}
|
||||||
|
|
||||||
MOCK_METHOD2(InitializeWithIv,
|
MOCK_METHOD2(InitializeWithIv,
|
||||||
bool(const std::vector<uint8_t>& key,
|
bool(const std::vector<uint8_t>& key,
|
||||||
const std::vector<uint8_t>& iv));
|
const std::vector<uint8_t>& iv));
|
||||||
MOCK_METHOD1(SetIv, bool(const std::vector<uint8_t>& iv));
|
|
||||||
MOCK_METHOD0(UpdateIv, void());
|
|
||||||
MOCK_METHOD4(CryptInternal,
|
MOCK_METHOD4(CryptInternal,
|
||||||
bool(const uint8_t* text,
|
bool(const uint8_t* text,
|
||||||
size_t text_size,
|
size_t text_size,
|
||||||
uint8_t* crypt_text,
|
uint8_t* crypt_text,
|
||||||
size_t* crypt_text_size));
|
size_t* crypt_text_size));
|
||||||
|
MOCK_METHOD0(SetIvInternal, void());
|
||||||
};
|
};
|
||||||
|
|
||||||
class AesPatternCryptorTest : public ::testing::Test {
|
class AesPatternCryptorTest : public ::testing::Test {
|
||||||
|
@ -42,7 +43,7 @@ class AesPatternCryptorTest : public ::testing::Test {
|
||||||
: mock_cryptor_(new MockAesCryptor),
|
: mock_cryptor_(new MockAesCryptor),
|
||||||
pattern_cryptor_(kCryptByteBlock,
|
pattern_cryptor_(kCryptByteBlock,
|
||||||
kSkipByteBlock,
|
kSkipByteBlock,
|
||||||
AesPatternCryptor::kDontUseConstantIv,
|
AesCryptor::kDontUseConstantIv,
|
||||||
scoped_ptr<MockAesCryptor>(mock_cryptor_)) {}
|
scoped_ptr<MockAesCryptor>(mock_cryptor_)) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -55,11 +56,7 @@ TEST_F(AesPatternCryptorTest, InitializeWithIv) {
|
||||||
std::vector<uint8_t> iv(8, 'i');
|
std::vector<uint8_t> iv(8, 'i');
|
||||||
EXPECT_CALL(*mock_cryptor_, InitializeWithIv(key, iv)).WillOnce(Return(true));
|
EXPECT_CALL(*mock_cryptor_, InitializeWithIv(key, iv)).WillOnce(Return(true));
|
||||||
EXPECT_TRUE(pattern_cryptor_.InitializeWithIv(key, iv));
|
EXPECT_TRUE(pattern_cryptor_.InitializeWithIv(key, iv));
|
||||||
}
|
EXPECT_EQ(iv, pattern_cryptor_.iv());
|
||||||
|
|
||||||
TEST_F(AesPatternCryptorTest, UpdateIv) {
|
|
||||||
EXPECT_CALL(*mock_cryptor_, UpdateIv());
|
|
||||||
pattern_cryptor_.UpdateIv();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -152,7 +149,7 @@ TEST(AesPatternCryptorConstIvTest, UseConstantIv) {
|
||||||
// SetIv will be called twice:
|
// SetIv will be called twice:
|
||||||
// once by AesPatternCryptor::SetIv,
|
// once by AesPatternCryptor::SetIv,
|
||||||
// once by AesPatternCryptor::Crypt, to make sure the same iv is used.
|
// 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));
|
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
|
||||||
|
|
||||||
std::string crypt_text;
|
std::string crypt_text;
|
||||||
|
@ -167,7 +164,7 @@ TEST(AesPatternCryptorConstIvTest, DontUseConstantIv) {
|
||||||
|
|
||||||
std::vector<uint8_t> iv(8, 'i');
|
std::vector<uint8_t> iv(8, 'i');
|
||||||
// SetIv will be called only once by AesPatternCryptor::SetIv.
|
// 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));
|
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
|
||||||
|
|
||||||
std::string crypt_text;
|
std::string crypt_text;
|
||||||
|
|
|
@ -46,22 +46,19 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
|
||||||
aes_decryptor.reset(new AesCtrDecryptor);
|
aes_decryptor.reset(new AesCtrDecryptor);
|
||||||
break;
|
break;
|
||||||
case FOURCC_cbc1:
|
case FOURCC_cbc1:
|
||||||
aes_decryptor.reset(new AesCbcDecryptor(kNoPadding, kChainAcrossCalls));
|
aes_decryptor.reset(new AesCbcDecryptor(kNoPadding));
|
||||||
break;
|
break;
|
||||||
case FOURCC_cens:
|
case FOURCC_cens:
|
||||||
aes_decryptor.reset(
|
aes_decryptor.reset(new AesPatternCryptor(
|
||||||
new AesPatternCryptor(decrypt_config->crypt_byte_block(),
|
decrypt_config->crypt_byte_block(),
|
||||||
decrypt_config->skip_byte_block(),
|
decrypt_config->skip_byte_block(), AesCryptor::kDontUseConstantIv,
|
||||||
AesPatternCryptor::kDontUseConstantIv,
|
scoped_ptr<AesCryptor>(new AesCtrDecryptor)));
|
||||||
scoped_ptr<AesCryptor>(new AesCtrDecryptor)));
|
|
||||||
break;
|
break;
|
||||||
case FOURCC_cbcs:
|
case FOURCC_cbcs:
|
||||||
aes_decryptor.reset(
|
aes_decryptor.reset(new AesPatternCryptor(
|
||||||
new AesPatternCryptor(decrypt_config->crypt_byte_block(),
|
decrypt_config->crypt_byte_block(),
|
||||||
decrypt_config->skip_byte_block(),
|
decrypt_config->skip_byte_block(), AesCryptor::kUseConstantIv,
|
||||||
AesPatternCryptor::kUseConstantIv,
|
scoped_ptr<AesCryptor>(new AesCbcDecryptor(kNoPadding))));
|
||||||
scoped_ptr<AesCryptor>(new AesCbcDecryptor(
|
|
||||||
kNoPadding, kChainAcrossCalls))));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(ERROR) << "Unsupported protection scheme: "
|
LOG(ERROR) << "Unsupported protection scheme: "
|
||||||
|
|
|
@ -41,7 +41,7 @@ AesRequestSigner* AesRequestSigner::CreateSigner(const std::string& signer_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_ptr<AesCbcEncryptor> encryptor(
|
scoped_ptr<AesCbcEncryptor> encryptor(
|
||||||
new AesCbcEncryptor(kPkcs5Padding, !kChainAcrossCalls));
|
new AesCbcEncryptor(kPkcs5Padding, AesCryptor::kUseConstantIv));
|
||||||
if (!encryptor->InitializeWithIv(aes_key, iv))
|
if (!encryptor->InitializeWithIv(aes_key, iv))
|
||||||
return NULL;
|
return NULL;
|
||||||
return new AesRequestSigner(signer_name, encryptor.Pass());
|
return new AesRequestSigner(signer_name, encryptor.Pass());
|
||||||
|
|
|
@ -197,20 +197,17 @@ Status EncryptingFragmenter::CreateEncryptor() {
|
||||||
encryptor.reset(new AesCtrEncryptor);
|
encryptor.reset(new AesCtrEncryptor);
|
||||||
break;
|
break;
|
||||||
case FOURCC_cbc1:
|
case FOURCC_cbc1:
|
||||||
encryptor.reset(new AesCbcEncryptor(kNoPadding, kChainAcrossCalls));
|
encryptor.reset(new AesCbcEncryptor(kNoPadding));
|
||||||
break;
|
break;
|
||||||
case FOURCC_cens:
|
case FOURCC_cens:
|
||||||
encryptor.reset(
|
encryptor.reset(new AesPatternCryptor(
|
||||||
new AesPatternCryptor(crypt_byte_block(), skip_byte_block(),
|
crypt_byte_block(), skip_byte_block(), AesCryptor::kDontUseConstantIv,
|
||||||
AesPatternCryptor::kDontUseConstantIv,
|
scoped_ptr<AesCryptor>(new AesCtrEncryptor)));
|
||||||
scoped_ptr<AesCryptor>(new AesCtrEncryptor)));
|
|
||||||
break;
|
break;
|
||||||
case FOURCC_cbcs:
|
case FOURCC_cbcs:
|
||||||
encryptor.reset(
|
encryptor.reset(new AesPatternCryptor(
|
||||||
new AesPatternCryptor(crypt_byte_block(), skip_byte_block(),
|
crypt_byte_block(), skip_byte_block(), AesCryptor::kUseConstantIv,
|
||||||
AesPatternCryptor::kUseConstantIv,
|
scoped_ptr<AesCryptor>(new AesCbcEncryptor(kNoPadding))));
|
||||||
scoped_ptr<AesCryptor>(new AesCbcEncryptor(
|
|
||||||
kNoPadding, kChainAcrossCalls))));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return Status(error::MUXER_FAILURE, "Unsupported protection scheme.");
|
return Status(error::MUXER_FAILURE, "Unsupported protection scheme.");
|
||||||
|
|
|
@ -1114,7 +1114,7 @@ bool WvmMediaParser::ProcessEcm() {
|
||||||
encryption_key.key.begin(),
|
encryption_key.key.begin(),
|
||||||
encryption_key.key.begin() + kAssetKeySizeBytes);
|
encryption_key.key.begin() + kAssetKeySizeBytes);
|
||||||
std::vector<uint8_t> iv(kInitializationVectorSizeBytes);
|
std::vector<uint8_t> iv(kInitializationVectorSizeBytes);
|
||||||
AesCbcDecryptor asset_decryptor(kCtsPadding, !kChainAcrossCalls);
|
AesCbcDecryptor asset_decryptor(kCtsPadding, AesCryptor::kUseConstantIv);
|
||||||
if (!asset_decryptor.InitializeWithIv(asset_key, iv)) {
|
if (!asset_decryptor.InitializeWithIv(asset_key, iv)) {
|
||||||
LOG(ERROR) << "Failed to initialize asset_decryptor.";
|
LOG(ERROR) << "Failed to initialize asset_decryptor.";
|
||||||
return false;
|
return false;
|
||||||
|
@ -1131,7 +1131,7 @@ bool WvmMediaParser::ProcessEcm() {
|
||||||
content_key_buffer.begin() + 4,
|
content_key_buffer.begin() + 4,
|
||||||
content_key_buffer.begin() + 20);
|
content_key_buffer.begin() + 20);
|
||||||
scoped_ptr<AesCbcDecryptor> content_decryptor(
|
scoped_ptr<AesCbcDecryptor> content_decryptor(
|
||||||
new AesCbcDecryptor(kCtsPadding, !kChainAcrossCalls));
|
new AesCbcDecryptor(kCtsPadding, AesCryptor::kUseConstantIv));
|
||||||
if (!content_decryptor->InitializeWithIv(decrypted_content_key_vec, iv)) {
|
if (!content_decryptor->InitializeWithIv(decrypted_content_key_vec, iv)) {
|
||||||
LOG(ERROR) << "Failed to initialize content decryptor.";
|
LOG(ERROR) << "Failed to initialize content decryptor.";
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue