More cleanups in AesEncryptor and AesDecryptor

- Create AesCryptor class as the common base
- AesCryptor::Crypt function will serve as an Encrypt function for
  encryptor and a Decrypt function for Decryptor.

Change-Id: Ie91fb14964b5091786705bf510656f40d73af160
This commit is contained in:
KongQun Yang 2016-04-05 17:19:16 -07:00
parent e92556658e
commit 5fc09763ce
14 changed files with 307 additions and 331 deletions

View File

@ -0,0 +1,59 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "packager/media/base/aes_cryptor.h"
#include <openssl/aes.h>
#include "packager/base/logging.h"
#include "packager/base/stl_util.h"
namespace edash_packager {
namespace media {
AesCryptor::AesCryptor() : aes_key_(new AES_KEY) {}
AesCryptor::~AesCryptor() {}
bool AesCryptor::Crypt(const std::vector<uint8_t>& text,
std::vector<uint8_t>* crypt_text) {
// Save text size to make it work for in-place conversion, since the
// next statement will update the text size.
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)) {
return false;
}
DCHECK_LE(crypt_text_size, crypt_text->size());
crypt_text->resize(crypt_text_size);
return true;
}
bool AesCryptor::Crypt(const std::string& text, std::string* crypt_text) {
// Save text size to make it work for in-place conversion, since the
// next statement will update the text size.
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,
reinterpret_cast<uint8_t*>(string_as_array(crypt_text)),
&crypt_text_size))
return false;
DCHECK_LE(crypt_text_size, crypt_text->size());
crypt_text->resize(crypt_text_size);
return true;
}
size_t AesCryptor::NumPaddingBytes(size_t size) const {
// No padding by default.
return 0;
}
} // namespace media
} // namespace edash_packager

View File

@ -0,0 +1,100 @@
// Copyright 2016 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef PACKAGER_MEDIA_BASE_AES_CRYPTOR_H_
#define PACKAGER_MEDIA_BASE_AES_CRYPTOR_H_
#include <string>
#include <vector>
#include "packager/base/macros.h"
#include "packager/base/memory/scoped_ptr.h"
struct aes_key_st;
typedef struct aes_key_st AES_KEY;
namespace edash_packager {
namespace media {
// AES cryptor interface. Inherited by various AES encryptor and decryptor
// implementations.
class AesCryptor {
public:
AesCryptor();
virtual ~AesCryptor();
/// Initialize the cryptor with specified key and IV.
/// @return true on successful initialization, false otherwise.
virtual bool InitializeWithIv(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv) = 0;
/// @name Various forms of crypt (Encrypt/Decrypt) calls.
/// It is an Encrypt function for encryptor and a Decrypt function for
/// decryptor. The text and crypt_text pointers can be the same address for
/// in place encryption/decryption.
/// @{
bool Crypt(const std::vector<uint8_t>& text,
std::vector<uint8_t>* crypt_text);
bool Crypt(const std::string& text, std::string* crypt_text);
/// @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);
}
/// @}
/// Set IV.
/// @return true if successful, false if the input is invalid.
virtual bool SetIv(const std::vector<uint8_t>& iv) = 0;
/// 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;
/// @return The current iv.
const std::vector<uint8_t>& iv() const { return 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(); }
private:
// Internal implementation of crypt function.
// |text| points to the input text.
// |text_size| is the size of input text.
// |crypt_text| points to the output encrypted or decrypted text, depends on
// whether it is an encryption or decryption. |text| and |crypt_text| can
// point to the same address for in place encryption/decryption.
// |crypt_text_size| contains the size of |crypt_text| and it will be updated
// to contain the actual encrypted/decrypted size for |crypt_text| on success.
// Return false if the input |crypt_text_size| is not large enough to hold the
// output |crypt_text| or if there is any error in encryption/decryption.
virtual bool CryptInternal(const uint8_t* text,
size_t text_size,
uint8_t* crypt_text,
size_t* crypt_text_size) = 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_;
DISALLOW_COPY_AND_ASSIGN(AesCryptor);
};
} // namespace media
} // namespace edash_packager
#endif // PACKAGER_MEDIA_BASE_AES_CRYPTOR_H_

View File

@ -159,22 +159,22 @@ class AesCtrEncryptorTest : public testing::Test {
TEST_F(AesCtrEncryptorTest, NistTestCase) { TEST_F(AesCtrEncryptorTest, NistTestCase) {
std::vector<uint8_t> encrypted; std::vector<uint8_t> encrypted;
EXPECT_TRUE(encryptor_.Encrypt(plaintext_, &encrypted)); ASSERT_TRUE(encryptor_.Crypt(plaintext_, &encrypted));
EXPECT_EQ(ciphertext_, encrypted); EXPECT_EQ(ciphertext_, encrypted);
EXPECT_TRUE(decryptor_.SetIv(iv_)); ASSERT_TRUE(decryptor_.SetIv(iv_));
std::vector<uint8_t> decrypted; std::vector<uint8_t> decrypted;
EXPECT_TRUE(decryptor_.Decrypt(encrypted, &decrypted)); ASSERT_TRUE(decryptor_.Crypt(encrypted, &decrypted));
EXPECT_EQ(plaintext_, decrypted); EXPECT_EQ(plaintext_, decrypted);
} }
TEST_F(AesCtrEncryptorTest, NistTestCaseInplaceEncryptionDecryption) { TEST_F(AesCtrEncryptorTest, NistTestCaseInplaceEncryptionDecryption) {
std::vector<uint8_t> buffer = plaintext_; std::vector<uint8_t> buffer = plaintext_;
EXPECT_TRUE(encryptor_.Encrypt(&buffer[0], buffer.size(), &buffer[0])); ASSERT_TRUE(encryptor_.Crypt(&buffer[0], buffer.size(), &buffer[0]));
EXPECT_EQ(ciphertext_, buffer); EXPECT_EQ(ciphertext_, buffer);
EXPECT_TRUE(decryptor_.SetIv(iv_)); ASSERT_TRUE(decryptor_.SetIv(iv_));
EXPECT_TRUE(decryptor_.Decrypt(&buffer[0], buffer.size(), &buffer[0])); ASSERT_TRUE(decryptor_.Crypt(&buffer[0], buffer.size(), &buffer[0]));
EXPECT_EQ(plaintext_, buffer); EXPECT_EQ(plaintext_, buffer);
} }
@ -184,13 +184,13 @@ TEST_F(AesCtrEncryptorTest, EncryptDecryptString) {
"82E3AD1EF90C5CC09EB37F1B9EFBD99016441A1C15123F0777CD57BB993E14DA02"; "82E3AD1EF90C5CC09EB37F1B9EFBD99016441A1C15123F0777CD57BB993E14DA02";
std::string ciphertext; std::string ciphertext;
EXPECT_TRUE(encryptor_.Encrypt(kPlaintext, &ciphertext)); ASSERT_TRUE(encryptor_.Crypt(kPlaintext, &ciphertext));
EXPECT_EQ(kExpectedCiphertextInHex, EXPECT_EQ(kExpectedCiphertextInHex,
base::HexEncode(ciphertext.data(), ciphertext.size())); base::HexEncode(ciphertext.data(), ciphertext.size()));
std::string decrypted; std::string decrypted;
EXPECT_TRUE(decryptor_.SetIv(iv_)); ASSERT_TRUE(decryptor_.SetIv(iv_));
EXPECT_TRUE(decryptor_.Decrypt(ciphertext, &decrypted)); ASSERT_TRUE(decryptor_.Crypt(ciphertext, &decrypted));
EXPECT_EQ(kPlaintext, decrypted); EXPECT_EQ(kPlaintext, decrypted);
} }
@ -202,7 +202,7 @@ TEST_F(AesCtrEncryptorTest, 128BitIVBoundaryCaseEncryption) {
kIv128Max64 + arraysize(kIv128Max64)); kIv128Max64 + arraysize(kIv128Max64));
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_max64)); ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_max64));
std::vector<uint8_t> encrypted; std::vector<uint8_t> encrypted;
EXPECT_TRUE(encryptor_.Encrypt(plaintext_, &encrypted)); ASSERT_TRUE(encryptor_.Crypt(plaintext_, &encrypted));
std::vector<uint8_t> iv_one_and_three( std::vector<uint8_t> iv_one_and_three(
kIv128OneAndThree, kIv128OneAndThree + arraysize(kIv128OneAndThree)); kIv128OneAndThree, kIv128OneAndThree + arraysize(kIv128OneAndThree));
@ -211,12 +211,12 @@ TEST_F(AesCtrEncryptorTest, 128BitIVBoundaryCaseEncryption) {
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_max64)); ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_max64));
std::vector<uint8_t> encrypted_verify(plaintext_.size(), 0); std::vector<uint8_t> encrypted_verify(plaintext_.size(), 0);
EXPECT_TRUE( ASSERT_TRUE(
encryptor_.Encrypt(&plaintext_[0], kAesBlockSize, &encrypted_verify[0])); encryptor_.Crypt(&plaintext_[0], kAesBlockSize, &encrypted_verify[0]));
std::vector<uint8_t> iv_zero(kIv128Zero, kIv128Zero + arraysize(kIv128Zero)); std::vector<uint8_t> iv_zero(kIv128Zero, kIv128Zero + arraysize(kIv128Zero));
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_zero)); ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_zero));
EXPECT_TRUE(encryptor_.Encrypt(&plaintext_[kAesBlockSize], kAesBlockSize * 3, ASSERT_TRUE(encryptor_.Crypt(&plaintext_[kAesBlockSize], kAesBlockSize * 3,
&encrypted_verify[kAesBlockSize])); &encrypted_verify[kAesBlockSize]));
EXPECT_EQ(encrypted, encrypted_verify); EXPECT_EQ(encrypted, encrypted_verify);
} }
@ -224,8 +224,8 @@ TEST_F(AesCtrEncryptorTest, InitWithRandomIv) {
const uint8_t kIvSize = 8; const uint8_t kIvSize = 8;
ASSERT_TRUE(encryptor_.InitializeWithRandomIv(key_, kIvSize)); ASSERT_TRUE(encryptor_.InitializeWithRandomIv(key_, kIvSize));
ASSERT_EQ(kIvSize, encryptor_.iv().size()); ASSERT_EQ(kIvSize, encryptor_.iv().size());
LOG(INFO) << "Random IV: " << base::HexEncode(&encryptor_.iv()[0], LOG(INFO) << "Random IV: "
encryptor_.iv().size()); << base::HexEncode(&encryptor_.iv()[0], encryptor_.iv().size());
} }
TEST_F(AesCtrEncryptorTest, UnsupportedKeySize) { TEST_F(AesCtrEncryptorTest, UnsupportedKeySize) {
@ -252,19 +252,17 @@ TEST_P(AesCtrEncryptorSubsampleTest, NistTestCaseSubsamples) {
std::vector<uint8_t> encrypted(plaintext_.size(), 0); std::vector<uint8_t> encrypted(plaintext_.size(), 0);
for (uint32_t i = 0, offset = 0; i < test_case->subsample_count; ++i) { for (uint32_t i = 0, offset = 0; i < test_case->subsample_count; ++i) {
uint32_t len = test_case->subsample_sizes[i]; uint32_t len = test_case->subsample_sizes[i];
EXPECT_TRUE( ASSERT_TRUE(encryptor_.Crypt(&plaintext_[offset], len, &encrypted[offset]));
encryptor_.Encrypt(&plaintext_[offset], len, &encrypted[offset]));
offset += len; offset += len;
EXPECT_EQ(offset % kAesBlockSize, encryptor_.block_offset()); EXPECT_EQ(offset % kAesBlockSize, encryptor_.block_offset());
} }
EXPECT_EQ(ciphertext_, encrypted); EXPECT_EQ(ciphertext_, encrypted);
EXPECT_TRUE(decryptor_.SetIv(iv_)); ASSERT_TRUE(decryptor_.SetIv(iv_));
std::vector<uint8_t> decrypted(encrypted.size(), 0); std::vector<uint8_t> decrypted(encrypted.size(), 0);
for (uint32_t i = 0, offset = 0; i < test_case->subsample_count; ++i) { for (uint32_t i = 0, offset = 0; i < test_case->subsample_count; ++i) {
uint32_t len = test_case->subsample_sizes[i]; uint32_t len = test_case->subsample_sizes[i];
EXPECT_TRUE( ASSERT_TRUE(decryptor_.Crypt(&encrypted[offset], len, &decrypted[offset]));
decryptor_.Decrypt(&encrypted[offset], len, &decrypted[offset]));
offset += len; offset += len;
EXPECT_EQ(offset % kAesBlockSize, decryptor_.block_offset()); EXPECT_EQ(offset % kAesBlockSize, decryptor_.block_offset());
} }
@ -291,7 +289,7 @@ TEST_P(AesCtrEncryptorIvTest, IvTest) {
ASSERT_TRUE(encryptor.InitializeWithIv(key, iv_test)); ASSERT_TRUE(encryptor.InitializeWithIv(key, iv_test));
std::vector<uint8_t> encrypted; std::vector<uint8_t> encrypted;
EXPECT_TRUE(encryptor.Encrypt(plaintext, &encrypted)); ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
encryptor.UpdateIv(); encryptor.UpdateIv();
EXPECT_EQ(iv_expected, encryptor.iv()); EXPECT_EQ(iv_expected, encryptor.iv());
} }
@ -300,9 +298,9 @@ INSTANTIATE_TEST_CASE_P(IvTestCases,
AesCtrEncryptorIvTest, AesCtrEncryptorIvTest,
::testing::ValuesIn(kIvTestCases)); ::testing::ValuesIn(kIvTestCases));
class AesCbcEncryptDecryptTest { class AesCbcTest : public ::testing::Test {
public: public:
AesCbcEncryptDecryptTest() AesCbcTest()
: encryptor_(new AesCbcEncryptor(kPkcs5Padding, !kChainAcrossCalls)), : encryptor_(new AesCbcEncryptor(kPkcs5Padding, !kChainAcrossCalls)),
decryptor_(new AesCbcDecryptor(kPkcs5Padding, !kChainAcrossCalls)), decryptor_(new AesCbcDecryptor(kPkcs5Padding, !kChainAcrossCalls)),
key_(kAesKey, kAesKey + arraysize(kAesKey)), key_(kAesKey, kAesKey + arraysize(kAesKey)),
@ -330,11 +328,11 @@ class AesCbcEncryptDecryptTest {
ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_)); ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_));
T encrypted; T encrypted;
EXPECT_TRUE(encryptor_->Encrypt(plaintext, &encrypted)); ASSERT_TRUE(encryptor_->Crypt(plaintext, &encrypted));
EXPECT_EQ(expected_ciphertext, encrypted); EXPECT_EQ(expected_ciphertext, encrypted);
T decrypted; T decrypted;
EXPECT_TRUE(decryptor_->Decrypt(encrypted, &decrypted)); ASSERT_TRUE(decryptor_->Crypt(encrypted, &decrypted));
EXPECT_EQ(plaintext, decrypted); EXPECT_EQ(plaintext, decrypted);
} }
@ -345,9 +343,9 @@ class AesCbcEncryptDecryptTest {
ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_)); ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_));
T buffer(plaintext); T buffer(plaintext);
EXPECT_TRUE(encryptor_->Encrypt(buffer, &buffer)); ASSERT_TRUE(encryptor_->Crypt(buffer, &buffer));
EXPECT_EQ(expected_ciphertext, buffer); EXPECT_EQ(expected_ciphertext, buffer);
EXPECT_TRUE(decryptor_->Decrypt(buffer, &buffer)); ASSERT_TRUE(decryptor_->Crypt(buffer, &buffer));
EXPECT_EQ(plaintext, buffer); EXPECT_EQ(plaintext, buffer);
} }
@ -357,8 +355,6 @@ class AesCbcEncryptDecryptTest {
std::vector<uint8_t> iv_; std::vector<uint8_t> iv_;
}; };
class AesCbcTest : public AesCbcEncryptDecryptTest, public testing::Test {};
TEST_F(AesCbcTest, Aes256CbcPkcs5) { TEST_F(AesCbcTest, Aes256CbcPkcs5) {
// NIST SP 800-38A test vector F.2.5 CBC-AES256.Encrypt. // NIST SP 800-38A test vector F.2.5 CBC-AES256.Encrypt.
static const uint8_t kAesCbcKey[] = { static const uint8_t kAesCbcKey[] = {
@ -462,22 +458,22 @@ TEST_F(AesCbcTest, NoPaddingNoChainAcrossCalls) {
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.Encrypt(plaintext, &encrypted)); ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
EXPECT_EQ(ciphertext, encrypted); EXPECT_EQ(ciphertext, encrypted);
// Iv should not have been updated. // Iv should not have been updated.
EXPECT_EQ(iv_, encryptor.iv()); EXPECT_EQ(iv_, encryptor.iv());
ASSERT_TRUE(encryptor.Encrypt(plaintext, &encrypted)); ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
EXPECT_EQ(ciphertext, encrypted); EXPECT_EQ(ciphertext, encrypted);
AesCbcDecryptor decryptor(kNoPadding, !kChainAcrossCalls); AesCbcDecryptor decryptor(kNoPadding, !kChainAcrossCalls);
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.Decrypt(ciphertext, &decrypted)); ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
EXPECT_EQ(plaintext, decrypted); EXPECT_EQ(plaintext, decrypted);
// Iv should not have been updated. // Iv should not have been updated.
EXPECT_EQ(iv_, encryptor.iv()); EXPECT_EQ(iv_, encryptor.iv());
ASSERT_TRUE(decryptor.Decrypt(ciphertext, &decrypted)); ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
EXPECT_EQ(plaintext, decrypted); EXPECT_EQ(plaintext, decrypted);
} }
@ -506,24 +502,24 @@ TEST_F(AesCbcTest, NoPaddingChainAcrossCalls) {
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.Encrypt(plaintext, &encrypted)); ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
EXPECT_EQ(ciphertext, encrypted); EXPECT_EQ(ciphertext, encrypted);
// Iv should have been updated. // Iv should have been updated.
EXPECT_NE(iv_, encryptor.iv()); 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.Encrypt(plaintext, &encrypted)); ASSERT_TRUE(encryptor.Crypt(plaintext, &encrypted));
EXPECT_EQ(ciphertext2, encrypted); EXPECT_EQ(ciphertext2, encrypted);
AesCbcDecryptor decryptor(kNoPadding, kChainAcrossCalls); AesCbcDecryptor decryptor(kNoPadding, kChainAcrossCalls);
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.Decrypt(ciphertext, &decrypted)); ASSERT_TRUE(decryptor.Crypt(ciphertext, &decrypted));
EXPECT_EQ(plaintext, decrypted); EXPECT_EQ(plaintext, decrypted);
// Iv should have been updated. // Iv should have been updated.
EXPECT_NE(iv_, encryptor.iv()); 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.Decrypt(ciphertext2, &decrypted)); ASSERT_TRUE(decryptor.Crypt(ciphertext2, &decrypted));
EXPECT_EQ(plaintext, decrypted); EXPECT_EQ(plaintext, decrypted);
} }
@ -540,13 +536,13 @@ TEST_F(AesCbcTest, UnsupportedIvSize) {
TEST_F(AesCbcTest, Pkcs5CipherTextNotMultipleOfBlockSize) { TEST_F(AesCbcTest, Pkcs5CipherTextNotMultipleOfBlockSize) {
std::string plaintext; std::string plaintext;
ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_)); ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_));
EXPECT_FALSE(decryptor_->Decrypt("1", &plaintext)); EXPECT_FALSE(decryptor_->Crypt("1", &plaintext));
} }
TEST_F(AesCbcTest, Pkcs5CipherTextEmpty) { TEST_F(AesCbcTest, Pkcs5CipherTextEmpty) {
std::string plaintext; std::string plaintext;
ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_)); ASSERT_TRUE(decryptor_->InitializeWithIv(key_, iv_));
EXPECT_FALSE(decryptor_->Decrypt("", &plaintext)); EXPECT_FALSE(decryptor_->Crypt("", &plaintext));
} }
struct CbcTestCase { struct CbcTestCase {
@ -585,8 +581,8 @@ const CbcTestCase kCbcTestCases[] = {
}; };
class AesCbcCryptorVerificationTest class AesCbcCryptorVerificationTest
: public AesCbcEncryptDecryptTest, : public AesCbcTest,
public ::testing::TestWithParam<CbcTestCase> {}; public ::testing::WithParamInterface<CbcTestCase> {};
TEST_P(AesCbcCryptorVerificationTest, EncryptDecryptTest) { TEST_P(AesCbcCryptorVerificationTest, EncryptDecryptTest) {
encryptor_.reset( encryptor_.reset(

View File

@ -7,8 +7,6 @@
#include "packager/media/base/aes_decryptor.h" #include "packager/media/base/aes_decryptor.h"
#include <openssl/aes.h> #include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "packager/base/logging.h" #include "packager/base/logging.h"
@ -24,60 +22,6 @@ bool IsKeySizeValidForAes(size_t key_size) {
namespace edash_packager { namespace edash_packager {
namespace media { namespace media {
AesDecryptor::AesDecryptor() {}
AesDecryptor::~AesDecryptor() {}
bool AesDecryptor::Decrypt(const std::vector<uint8_t>& ciphertext,
std::vector<uint8_t>* plaintext) {
DCHECK(plaintext);
plaintext->resize(ciphertext.size());
size_t plaintext_size;
if (!DecryptInternal(ciphertext.data(), ciphertext.size(), plaintext->data(),
&plaintext_size))
return false;
plaintext->resize(plaintext_size);
return true;
}
bool AesDecryptor::Decrypt(const std::string& ciphertext,
std::string* plaintext) {
DCHECK(plaintext);
plaintext->resize(ciphertext.size());
size_t plaintext_size;
if (!DecryptInternal(reinterpret_cast<const uint8_t*>(ciphertext.data()),
ciphertext.size(),
reinterpret_cast<uint8_t*>(string_as_array(plaintext)),
&plaintext_size))
return false;
plaintext->resize(plaintext_size);
return true;
}
AesCtrDecryptor::AesCtrDecryptor() {}
AesCtrDecryptor::~AesCtrDecryptor() {}
bool AesCtrDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv) {
encryptor_.reset(new AesCtrEncryptor);
return encryptor_->InitializeWithIv(key, iv);
}
bool AesCtrDecryptor::SetIv(const std::vector<uint8_t>& iv) {
DCHECK(encryptor_);
return encryptor_->SetIv(iv);
}
bool AesCtrDecryptor::DecryptInternal(const uint8_t* ciphertext,
size_t ciphertext_size,
uint8_t* plaintext,
size_t* plaintext_size) {
DCHECK(encryptor_);
*plaintext_size = ciphertext_size;
// For AES CTR, encryption and decryption are identical.
return encryptor_->Encrypt(ciphertext, ciphertext_size, plaintext);
}
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme, AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
bool chain_across_calls) bool chain_across_calls)
: padding_scheme_(padding_scheme), : padding_scheme_(padding_scheme),
@ -87,6 +31,7 @@ AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
"sense if the padding_scheme is kNoPadding."; "sense if the padding_scheme is kNoPadding.";
} }
} }
AesCbcDecryptor::~AesCbcDecryptor() {} AesCbcDecryptor::~AesCbcDecryptor() {}
bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8_t>& key, bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
@ -96,9 +41,8 @@ bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
return false; return false;
} }
aes_key_.reset(new AES_KEY()); CHECK_EQ(AES_set_decrypt_key(key.data(), key.size() * 8, mutable_aes_key()),
CHECK_EQ(AES_set_decrypt_key(key.data(), key.size() * 8, aes_key_.get()), 0); 0);
return SetIv(iv); return SetIv(iv);
} }
@ -108,36 +52,43 @@ bool AesCbcDecryptor::SetIv(const std::vector<uint8_t>& iv) {
return false; return false;
} }
iv_ = iv; set_iv(iv);
return true; return true;
} }
bool AesCbcDecryptor::DecryptInternal(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,
size_t* plaintext_size) { size_t* plaintext_size) {
DCHECK(plaintext_size); DCHECK(plaintext_size);
DCHECK(aes_key_); DCHECK(aes_key());
// Plaintext size is the same as ciphertext size except for pkcs5 padding. // Plaintext size is the same as ciphertext size except for pkcs5 padding.
// Will update later if using pkcs5 padding. // Will update later if using pkcs5 padding. For pkcs5 padding, we still
// need at least |ciphertext_size| bytes for intermediate operation.
if (*plaintext_size < ciphertext_size) {
LOG(ERROR) << "Expecting output size of at least " << ciphertext_size
<< " bytes.";
return false;
}
*plaintext_size = ciphertext_size; *plaintext_size = ciphertext_size;
if (ciphertext_size == 0) { if (ciphertext_size == 0) {
if (padding_scheme_ == kPkcs5Padding) { if (padding_scheme_ == kPkcs5Padding) {
LOG(ERROR) << "Expected ciphertext to be at least " << AES_BLOCK_SIZE LOG(ERROR) << "Expected ciphertext to be at least " << AES_BLOCK_SIZE
<< " bytes with Pkcs5 padding"; << " bytes with Pkcs5 padding.";
return false; return false;
} }
return true; return true;
} }
DCHECK(plaintext); DCHECK(plaintext);
std::vector<uint8_t> local_iv(iv_); 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;
if (residual_block_size == 0) { if (residual_block_size == 0) {
AES_cbc_encrypt(ciphertext, plaintext, ciphertext_size, aes_key_.get(), AES_cbc_encrypt(ciphertext, plaintext, ciphertext_size, aes_key(),
local_iv.data(), AES_DECRYPT); local_iv.data(), AES_DECRYPT);
if (chain_across_calls_) if (chain_across_calls_)
iv_ = local_iv; set_iv(local_iv);
if (padding_scheme_ != kPkcs5Padding) if (padding_scheme_ != kPkcs5Padding)
return true; return true;
@ -167,8 +118,8 @@ bool AesCbcDecryptor::DecryptInternal(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.
const size_t cbc_size = ciphertext_size - residual_block_size; const size_t cbc_size = ciphertext_size - residual_block_size;
if (cbc_size > AES_BLOCK_SIZE) { if (cbc_size > AES_BLOCK_SIZE) {
AES_cbc_encrypt(ciphertext, plaintext, cbc_size - AES_BLOCK_SIZE, AES_cbc_encrypt(ciphertext, plaintext, cbc_size - AES_BLOCK_SIZE, aes_key(),
aes_key_.get(), local_iv.data(), AES_DECRYPT); local_iv.data(), AES_DECRYPT);
} }
const uint8_t* next_to_last_ciphertext_block = const uint8_t* next_to_last_ciphertext_block =
@ -186,7 +137,7 @@ bool AesCbcDecryptor::DecryptInternal(const uint8_t* ciphertext,
// Decrypt the next-to-last block using the IV determined above. This decrypts // Decrypt the next-to-last block using the IV determined above. This decrypts
// the residual block bits. // the residual block bits.
AES_cbc_encrypt(next_to_last_ciphertext_block, next_to_last_plaintext_block, AES_cbc_encrypt(next_to_last_ciphertext_block, next_to_last_plaintext_block,
AES_BLOCK_SIZE, aes_key_.get(), last_iv.data(), AES_DECRYPT); AES_BLOCK_SIZE, aes_key(), last_iv.data(), AES_DECRYPT);
// Swap back the residual block bits and the next-to-last block. // Swap back the residual block bits and the next-to-last block.
if (plaintext == ciphertext) { if (plaintext == ciphertext) {
@ -202,7 +153,7 @@ bool AesCbcDecryptor::DecryptInternal(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_.get(), local_iv.data(), AES_DECRYPT); AES_BLOCK_SIZE, aes_key(), local_iv.data(), AES_DECRYPT);
return true; return true;
} }

View File

@ -6,98 +6,23 @@
// //
// AES Decryptor implementation using openssl. // AES Decryptor implementation using openssl.
#ifndef MEDIA_BASE_AES_DECRYPTOR_H_ #ifndef PACKAGER_MEDIA_BASE_AES_DECRYPTOR_H_
#define MEDIA_BASE_AES_DECRYPTOR_H_ #define PACKAGER_MEDIA_BASE_AES_DECRYPTOR_H_
#include <string>
#include <vector> #include <vector>
#include "packager/base/memory/scoped_ptr.h" #include "packager/base/macros.h"
#include "packager/base/stl_util.h" #include "packager/media/base/aes_cryptor.h"
#include "packager/media/base/aes_encryptor.h" #include "packager/media/base/aes_encryptor.h"
struct aes_key_st;
typedef struct aes_key_st AES_KEY;
namespace edash_packager { namespace edash_packager {
namespace media { namespace media {
class AesDecryptor { /// For AES-CTR, encryption and decryption are identical.
public: using AesCtrDecryptor = AesCtrEncryptor;
AesDecryptor();
virtual ~AesDecryptor();
/// Initialize the decryptor with specified key and IV. /// Class which implements AES-CBC (Cipher block chaining) decryption.
/// @return true on successful initialization, false otherwise. class AesCbcDecryptor : public AesCryptor {
virtual bool InitializeWithIv(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv) = 0;
/// @name Various forms of decrypt calls.
/// The plaintext and ciphertext pointers can be the same address.
/// @{
bool Decrypt(const std::vector<uint8_t>& ciphertext,
std::vector<uint8_t>* plaintext);
bool Decrypt(const std::string& ciphertext, std::string* plaintext);
bool Decrypt(const uint8_t* ciphertext,
size_t ciphertext_size,
uint8_t* plaintext) {
size_t plaintext_size;
return DecryptInternal(ciphertext, ciphertext_size, plaintext,
&plaintext_size);
}
/// @}
/// Set IV.
/// @return true if successful, false if the input is invalid.
virtual bool SetIv(const std::vector<uint8_t>& iv) = 0;
protected:
/// Internal implementation of decrypt function.
/// @param ciphertext points to the input ciphertext.
/// @param ciphertext_size is the input ciphertext size.
/// @param[out] plaintext points to the output plaintext. @a plaintext and
/// @a ciphertext can point to the same address.
/// @param[out] plaintext_size contains the size of plaintext on success.
/// It should never be larger than @a ciphertext_size.
virtual bool DecryptInternal(const uint8_t* ciphertext,
size_t ciphertext_size,
uint8_t* plaintext,
size_t* plaintext_size) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(AesDecryptor);
};
// Class which implements AES-CTR counter-mode decryption.
class AesCtrDecryptor : public AesDecryptor {
public:
AesCtrDecryptor();
~AesCtrDecryptor() override;
/// @name AesDecryptor 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;
/// @}
uint32_t block_offset() const { return encryptor_->block_offset(); }
protected:
bool DecryptInternal(const uint8_t* ciphertext,
size_t ciphertext_size,
uint8_t* plaintext,
size_t* plaintext_size) override;
private:
scoped_ptr<AesCtrEncryptor> encryptor_;
DISALLOW_COPY_AND_ASSIGN(AesCtrDecryptor);
};
// Class which implements AES-CBC (Cipher block chaining) decryption.
class AesCbcDecryptor : public AesDecryptor {
public: public:
/// @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.
@ -107,25 +32,22 @@ class AesCbcDecryptor : public AesDecryptor {
AesCbcDecryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls); AesCbcDecryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls);
~AesCbcDecryptor() override; ~AesCbcDecryptor() override;
/// @name AesDecryptor 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; bool SetIv(const std::vector<uint8_t>& iv) override;
void UpdateIv() override {
// Nop for decryptor.
}
/// @} /// @}
protected:
bool DecryptInternal(const uint8_t* ciphertext,
size_t ciphertext_size,
uint8_t* plaintext,
size_t* plaintext_size) override;
private: private:
// Openssl AES_KEY. bool CryptInternal(const uint8_t* ciphertext,
scoped_ptr<AES_KEY> aes_key_; size_t ciphertext_size,
// Initialization vector, must be 16 for CBC. uint8_t* plaintext,
std::vector<uint8_t> iv_; size_t* plaintext_size) override;
const CbcPaddingScheme padding_scheme_; const CbcPaddingScheme padding_scheme_;
const bool chain_across_calls_; const bool chain_across_calls_;
@ -135,4 +57,4 @@ class AesCbcDecryptor : public AesDecryptor {
} // namespace media } // namespace media
} // namespace edash_packager } // namespace edash_packager
#endif // MEDIA_BASE_AES_DECRYPTOR_H_ #endif // PACKAGER_MEDIA_BASE_AES_DECRYPTOR_H_

View File

@ -40,9 +40,8 @@ namespace media {
AesEncryptor::AesEncryptor() {} AesEncryptor::AesEncryptor() {}
AesEncryptor::~AesEncryptor() {} AesEncryptor::~AesEncryptor() {}
bool AesEncryptor::InitializeWithRandomIv( bool AesEncryptor::InitializeWithRandomIv(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& key, uint8_t iv_size) {
uint8_t iv_size) {
std::vector<uint8_t> iv(iv_size, 0); std::vector<uint8_t> iv(iv_size, 0);
if (RAND_bytes(iv.data(), iv_size) != 1) { if (RAND_bytes(iv.data(), iv_size) != 1) {
LOG(ERROR) << "RAND_bytes failed with error: " LOG(ERROR) << "RAND_bytes failed with error: "
@ -59,31 +58,11 @@ bool AesEncryptor::InitializeWithIv(const std::vector<uint8_t>& key,
return false; return false;
} }
aes_key_.reset(new AES_KEY()); CHECK_EQ(AES_set_encrypt_key(key.data(), key.size() * 8, mutable_aes_key()),
CHECK_EQ(AES_set_encrypt_key(key.data(), key.size() * 8, aes_key_.get()), 0); 0);
return SetIv(iv); return SetIv(iv);
} }
bool AesEncryptor::Encrypt(const std::vector<uint8_t>& plaintext,
std::vector<uint8_t>* ciphertext) {
// Save plaintext size to make it work for in-place conversion, since the
// next statement will update the plaintext size.
const size_t plaintext_size = plaintext.size();
ciphertext->resize(plaintext_size + NumPaddingBytes(plaintext.size()));
return EncryptInternal(plaintext.data(), plaintext_size, ciphertext->data());
}
bool AesEncryptor::Encrypt(const std::string& plaintext,
std::string* ciphertext) {
// Save plaintext size to make it work for in-place conversion, since the
// next statement will update the plaintext size.
const size_t plaintext_size = plaintext.size();
ciphertext->resize(plaintext_size + NumPaddingBytes(plaintext.size()));
return EncryptInternal(
reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext_size,
reinterpret_cast<uint8_t*>(string_as_array(ciphertext)));
}
AesCtrEncryptor::AesCtrEncryptor() AesCtrEncryptor::AesCtrEncryptor()
: block_offset_(0), : block_offset_(0),
encrypted_counter_(AES_BLOCK_SIZE, 0), encrypted_counter_(AES_BLOCK_SIZE, 0),
@ -134,13 +113,22 @@ bool AesCtrEncryptor::SetIv(const std::vector<uint8_t>& iv) {
return true; return true;
} }
bool AesCtrEncryptor::EncryptInternal(const uint8_t* plaintext, bool AesCtrEncryptor::CryptInternal(const uint8_t* plaintext,
size_t plaintext_size, size_t plaintext_size,
uint8_t* ciphertext) { uint8_t* ciphertext,
size_t* ciphertext_size) {
DCHECK(plaintext); DCHECK(plaintext);
DCHECK(ciphertext); DCHECK(ciphertext);
DCHECK(aes_key()); DCHECK(aes_key());
// |ciphertext_size| is always the same as |plaintext_size| for counter mode.
if (*ciphertext_size < plaintext_size) {
LOG(ERROR) << "Expecting output size of at least " << plaintext_size
<< " bytes.";
return false;
}
*ciphertext_size = plaintext_size;
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());
@ -158,11 +146,6 @@ bool AesCtrEncryptor::EncryptInternal(const uint8_t* plaintext,
return true; return true;
} }
size_t AesCtrEncryptor::NumPaddingBytes(size_t size) const {
// No padding needed for CTR.
return 0;
}
AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme, AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme,
bool chain_across_calls) bool chain_across_calls)
: padding_scheme_(padding_scheme), : padding_scheme_(padding_scheme),
@ -194,9 +177,10 @@ bool AesCbcEncryptor::SetIv(const std::vector<uint8_t>& iv) {
return true; return true;
} }
bool AesCbcEncryptor::EncryptInternal(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,
size_t* ciphertext_size) {
DCHECK(aes_key()); DCHECK(aes_key());
const size_t residual_block_size = plaintext_size % AES_BLOCK_SIZE; const size_t residual_block_size = plaintext_size % AES_BLOCK_SIZE;
@ -206,6 +190,15 @@ bool AesCbcEncryptor::EncryptInternal(const uint8_t* plaintext,
return false; return false;
} }
const size_t num_padding_bytes = NumPaddingBytes(plaintext_size);
const size_t required_ciphertext_size = plaintext_size + num_padding_bytes;
if (*ciphertext_size < required_ciphertext_size) {
LOG(ERROR) << "Expecting output size of at least "
<< required_ciphertext_size << " bytes.";
return false;
}
*ciphertext_size = required_ciphertext_size;
// 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()); std::vector<uint8_t> local_iv(iv());
@ -231,13 +224,14 @@ bool AesCbcEncryptor::EncryptInternal(const uint8_t* plaintext,
uint8_t* residual_ciphertext_block = ciphertext + cbc_size; uint8_t* residual_ciphertext_block = ciphertext + cbc_size;
if (padding_scheme_ == kPkcs5Padding) { if (padding_scheme_ == kPkcs5Padding) {
const size_t num_padding_bytes = AES_BLOCK_SIZE - residual_block_size; DCHECK_EQ(num_padding_bytes, AES_BLOCK_SIZE - residual_block_size);
DCHECK_EQ(num_padding_bytes, NumPaddingBytes(plaintext_size));
// 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(), local_iv.data(), AES_ENCRYPT);
} else { } else {
DCHECK_EQ(num_padding_bytes, 0u);
DCHECK_EQ(padding_scheme_, kCtsPadding); DCHECK_EQ(padding_scheme_, kCtsPadding);
// Zero-pad the residual block and encrypt using CBC. // Zero-pad the residual block and encrypt using CBC.

View File

@ -12,77 +12,29 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "packager/base/macros.h"
#include "packager/base/memory/scoped_ptr.h" #include "packager/base/memory/scoped_ptr.h"
#include "packager/base/stl_util.h" #include "packager/media/base/aes_cryptor.h"
struct aes_key_st;
typedef struct aes_key_st AES_KEY;
namespace edash_packager { namespace edash_packager {
namespace media { namespace media {
class AesEncryptor { class AesEncryptor : public AesCryptor {
public: public:
AesEncryptor(); AesEncryptor();
virtual ~AesEncryptor(); ~AesEncryptor() override;
/// Initialize the encryptor with specified key and a random generated IV /// Initialize the encryptor with specified key and a random generated IV
/// of the specified size. /// of the specified size.
/// @return true on successful initialization, false otherwise. /// @return true on successful initialization, false otherwise.
bool InitializeWithRandomIv(const std::vector<uint8_t>& key, bool InitializeWithRandomIv(const std::vector<uint8_t>& key, uint8_t iv_size);
uint8_t iv_size);
/// Initialize the encryptor with specified key and IV. /// Initialize the encryptor with specified key and IV.
/// @return true on successful initialization, false otherwise. /// @return true on successful initialization, false otherwise.
bool InitializeWithIv(const std::vector<uint8_t>& key, bool InitializeWithIv(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv); const std::vector<uint8_t>& iv) override;
/// @name Various forms of encrypt calls.
/// The plaintext and ciphertext pointers can be the same address.
bool Encrypt(const std::vector<uint8_t>& plaintext,
std::vector<uint8_t>* ciphertext);
bool Encrypt(const std::string& plaintext, std::string* ciphertext);
bool Encrypt(const uint8_t* plaintext,
size_t plaintext_size,
uint8_t* ciphertext) {
return EncryptInternal(plaintext, plaintext_size, ciphertext);
}
/// @}
/// Update IV for next sample.
/// As recommended in ISO/IEC FDIS 23001-7:
/// IV need to be updated per sample for CENC.
virtual void UpdateIv() = 0;
/// Set IV.
/// @return true if successful, false if the input is invalid.
virtual bool SetIv(const std::vector<uint8_t>& iv) = 0;
/// @return The current iv.
const std::vector<uint8_t>& iv() const { return iv_; }
protected:
/// Internal implementation of encrypt function.
/// @param plaintext points to the input plaintext.
/// @param plaintext_size is the size of input plaintext.
/// @param[out] ciphertext points to the output ciphertext. @a plaintext and
/// @a ciphertext can point to the same address.
virtual bool EncryptInternal(const uint8_t* plaintext,
size_t plaintext_size,
uint8_t* ciphertext) = 0;
/// @param size specifies the input plaintext size.
/// @returns The number of padding bytes needed for output ciphertext.
virtual size_t NumPaddingBytes(size_t size) const = 0;
void set_iv(const std::vector<uint8_t>& iv) { iv_ = iv; }
AES_KEY* aes_key() const { return aes_key_.get(); }
private: private:
// Initialization vector, with size 8 or 16.
std::vector<uint8_t> iv_;
// Openssl AES_KEY.
scoped_ptr<AES_KEY> aes_key_;
DISALLOW_COPY_AND_ASSIGN(AesEncryptor); DISALLOW_COPY_AND_ASSIGN(AesEncryptor);
}; };
@ -92,7 +44,7 @@ class AesCtrEncryptor : public AesEncryptor {
AesCtrEncryptor(); AesCtrEncryptor();
~AesCtrEncryptor() override; ~AesCtrEncryptor() override;
/// @name AesEncryptor implementation overrides. /// @name AesCryptor implementation overrides.
/// @{ /// @{
/// Update IV for next sample. @a block_offset_ is reset to 0. /// Update IV for next sample. @a block_offset_ is reset to 0.
/// As recommended in ISO/IEC FDIS 23001-7: CENC spec, /// As recommended in ISO/IEC FDIS 23001-7: CENC spec,
@ -105,13 +57,12 @@ class AesCtrEncryptor : public AesEncryptor {
uint32_t block_offset() const { return block_offset_; } uint32_t block_offset() const { return block_offset_; }
protected:
bool EncryptInternal(const uint8_t* plaintext,
size_t plaintext_size,
uint8_t* ciphertext) override;
size_t NumPaddingBytes(size_t size) const override;
private: private:
bool CryptInternal(const uint8_t* plaintext,
size_t plaintext_size,
uint8_t* ciphertext,
size_t* ciphertext_size) override;
// Current block offset. // Current block offset.
uint32_t block_offset_; uint32_t block_offset_;
// Current AES-CTR counter. // Current AES-CTR counter.
@ -143,20 +94,20 @@ class AesCbcEncryptor : public AesEncryptor {
AesCbcEncryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls); AesCbcEncryptor(CbcPaddingScheme padding_scheme, bool chain_across_calls);
~AesCbcEncryptor() override; ~AesCbcEncryptor() override;
/// @name AesEncryptor implementation overrides. /// @name AesCryptor implementation overrides.
/// @{ /// @{
void UpdateIv() override; void UpdateIv() override;
bool SetIv(const std::vector<uint8_t>& iv) override; bool SetIv(const std::vector<uint8_t>& iv) override;
/// @} /// @}
protected: private:
bool EncryptInternal(const uint8_t* plaintext, bool CryptInternal(const uint8_t* plaintext,
size_t plaintext_size, size_t plaintext_size,
uint8_t* ciphertext) override; uint8_t* ciphertext,
size_t* ciphertext_size) override;
size_t NumPaddingBytes(size_t size) const override; size_t NumPaddingBytes(size_t size) const override;
private:
const CbcPaddingScheme padding_scheme_; const CbcPaddingScheme padding_scheme_;
const bool chain_across_calls_; const bool chain_across_calls_;

View File

@ -27,7 +27,7 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
DCHECK(buffer); DCHECK(buffer);
// Get the decryptor object. // Get the decryptor object.
AesDecryptor* decryptor; AesCryptor* decryptor;
auto found = decryptor_map_.find(decrypt_config->key_id()); auto found = decryptor_map_.find(decrypt_config->key_id());
if (found == decryptor_map_.end()) { if (found == decryptor_map_.end()) {
// Create new AesDecryptor based on decryption mode. // Create new AesDecryptor based on decryption mode.
@ -38,7 +38,7 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
return false; return false;
} }
scoped_ptr<AesDecryptor> aes_decryptor; scoped_ptr<AesCryptor> aes_decryptor;
switch (decrypt_config->decryption_mode()) { switch (decrypt_config->decryption_mode()) {
case kEncryptionModeAesCtr: case kEncryptionModeAesCtr:
aes_decryptor.reset(new AesCtrDecryptor); aes_decryptor.reset(new AesCtrDecryptor);
@ -68,7 +68,7 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
if (decrypt_config->subsamples().empty()) { if (decrypt_config->subsamples().empty()) {
// Sample not encrypted using subsample encryption. Decrypt whole. // Sample not encrypted using subsample encryption. Decrypt whole.
if (!decryptor->Decrypt(buffer, buffer_size, buffer)) { if (!decryptor->Crypt(buffer, buffer_size, buffer)) {
LOG(ERROR) << "Error during bulk sample decryption."; LOG(ERROR) << "Error during bulk sample decryption.";
return false; return false;
} }
@ -86,7 +86,7 @@ bool DecryptorSource::DecryptSampleBuffer(const DecryptConfig* decrypt_config,
return false; return false;
} }
current_ptr += subsample.clear_bytes; current_ptr += subsample.clear_bytes;
if (!decryptor->Decrypt(current_ptr, subsample.cipher_bytes, current_ptr)) { if (!decryptor->Crypt(current_ptr, subsample.cipher_bytes, current_ptr)) {
LOG(ERROR) << "Error decrypting subsample buffer."; LOG(ERROR) << "Error decrypting subsample buffer.";
return false; return false;
} }

View File

@ -29,7 +29,7 @@ class DecryptorSource {
private: private:
KeySource* key_source_; KeySource* key_source_;
std::map<std::vector<uint8_t>, AesDecryptor*> decryptor_map_; std::map<std::vector<uint8_t>, AesCryptor*> decryptor_map_;
DISALLOW_COPY_AND_ASSIGN(DecryptorSource); DISALLOW_COPY_AND_ASSIGN(DecryptorSource);
}; };

View File

@ -13,6 +13,8 @@
'target_name': 'media_base', 'target_name': 'media_base',
'type': '<(component)', 'type': '<(component)',
'sources': [ 'sources': [
'aes_cryptor.cc',
'aes_cryptor.h',
'aes_decryptor.cc', 'aes_decryptor.cc',
'aes_decryptor.h', 'aes_decryptor.h',
'aes_encryptor.cc', 'aes_encryptor.cc',
@ -113,7 +115,7 @@
'target_name': 'media_base_unittest', 'target_name': 'media_base_unittest',
'type': '<(gtest_target_type)', 'type': '<(gtest_target_type)',
'sources': [ 'sources': [
'aes_encryptor_unittest.cc', 'aes_cryptor_unittest.cc',
'audio_timestamp_helper_unittest.cc', 'audio_timestamp_helper_unittest.cc',
'bit_reader_unittest.cc', 'bit_reader_unittest.cc',
'buffer_writer_unittest.cc', 'buffer_writer_unittest.cc',

View File

@ -6,6 +6,7 @@
#include "packager/media/base/request_signer.h" #include "packager/media/base/request_signer.h"
#include "packager/base/logging.h"
#include "packager/base/sha1.h" #include "packager/base/sha1.h"
#include "packager/base/strings/string_number_conversions.h" #include "packager/base/strings/string_number_conversions.h"
#include "packager/media/base/aes_encryptor.h" #include "packager/media/base/aes_encryptor.h"
@ -48,7 +49,7 @@ AesRequestSigner* AesRequestSigner::CreateSigner(const std::string& signer_name,
bool AesRequestSigner::GenerateSignature(const std::string& message, bool AesRequestSigner::GenerateSignature(const std::string& message,
std::string* signature) { std::string* signature) {
aes_cbc_encryptor_->Encrypt(base::SHA1HashString(message), signature); aes_cbc_encryptor_->Crypt(base::SHA1HashString(message), signature);
return true; return true;
} }

View File

@ -199,7 +199,7 @@ Status EncryptingFragmenter::CreateEncryptor() {
void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) { void EncryptingFragmenter::EncryptBytes(uint8_t* data, uint32_t size) {
DCHECK(encryptor_); DCHECK(encryptor_);
CHECK(encryptor_->Encrypt(data, size, data)); CHECK(encryptor_->Crypt(data, size, data));
} }
Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) { Status EncryptingFragmenter::EncryptSample(scoped_refptr<MediaSample> sample) {

View File

@ -78,7 +78,7 @@ Status Encryptor::EncryptFrame(scoped_refptr<MediaSample> sample,
uint8_t* sample_data = sample->writable_data(); uint8_t* sample_data = sample->writable_data();
// Encrypt the data in-place. // Encrypt the data in-place.
if (!encryptor_->Encrypt(sample_data, sample_size, sample_data)) { if (!encryptor_->Crypt(sample_data, sample_size, sample_data)) {
return Status(error::MUXER_FAILURE, "Failed to encrypt the frame."); return Status(error::MUXER_FAILURE, "Failed to encrypt the frame.");
} }

View File

@ -779,9 +779,9 @@ bool WvmMediaParser::DemuxNextPes(bool is_program_end) {
if (!content_decryptor_) { if (!content_decryptor_) {
output_encrypted_sample = true; output_encrypted_sample = true;
} else { } else {
content_decryptor_->Decrypt(&sample_data_[crypto_unit_start_pos_], content_decryptor_->Crypt(&sample_data_[crypto_unit_start_pos_],
sample_data_.size() - crypto_unit_start_pos_, sample_data_.size() - crypto_unit_start_pos_,
&sample_data_[crypto_unit_start_pos_]); &sample_data_[crypto_unit_start_pos_]);
} }
} }
// Demux media sample if we are at program end or if we are not at a // Demux media sample if we are at program end or if we are not at a
@ -1124,8 +1124,8 @@ bool WvmMediaParser::ProcessEcm() {
kEcmFlagsSizeBytes + kEcmContentKeySizeBytes + kEcmFlagsSizeBytes + kEcmContentKeySizeBytes +
kEcmPaddingSizeBytes; // flags + contentKey + padding. kEcmPaddingSizeBytes; // flags + contentKey + padding.
std::vector<uint8_t> content_key_buffer(content_key_buffer_size); std::vector<uint8_t> content_key_buffer(content_key_buffer_size);
CHECK(asset_decryptor.Decrypt(ecm_data, content_key_buffer_size, CHECK(asset_decryptor.Crypt(ecm_data, content_key_buffer_size,
content_key_buffer.data())); content_key_buffer.data()));
std::vector<uint8_t> decrypted_content_key_vec( std::vector<uint8_t> decrypted_content_key_vec(
content_key_buffer.begin() + 4, content_key_buffer.begin() + 4,