Implemented AES-CBC with Ciphertext Stealing for WVM decryption.
Change-Id: I4a1ba4247bb6f055905663568699b06d7c18a968
This commit is contained in:
parent
3114ee945d
commit
fd35084722
|
@ -143,11 +143,11 @@ bool AesCtrEncryptor::SetIv(const std::vector<uint8>& iv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AesCbcEncryptor::AesCbcEncryptor() {}
|
AesCbcPkcs5Encryptor::AesCbcPkcs5Encryptor() {}
|
||||||
AesCbcEncryptor::~AesCbcEncryptor() {}
|
AesCbcPkcs5Encryptor::~AesCbcPkcs5Encryptor() {}
|
||||||
|
|
||||||
bool AesCbcEncryptor::InitializeWithIv(const std::vector<uint8>& key,
|
bool AesCbcPkcs5Encryptor::InitializeWithIv(const std::vector<uint8>& key,
|
||||||
const std::vector<uint8>& iv) {
|
const std::vector<uint8>& iv) {
|
||||||
if (!IsKeySizeValidForAes(key.size())) {
|
if (!IsKeySizeValidForAes(key.size())) {
|
||||||
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||||
return false;
|
return false;
|
||||||
|
@ -164,8 +164,8 @@ bool AesCbcEncryptor::InitializeWithIv(const std::vector<uint8>& key,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AesCbcEncryptor::Encrypt(const std::string& plaintext,
|
void AesCbcPkcs5Encryptor::Encrypt(const std::string& plaintext,
|
||||||
std::string* ciphertext) {
|
std::string* ciphertext) {
|
||||||
DCHECK(ciphertext);
|
DCHECK(ciphertext);
|
||||||
DCHECK(encrypt_key_);
|
DCHECK(encrypt_key_);
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ void AesCbcEncryptor::Encrypt(const std::string& plaintext,
|
||||||
AES_ENCRYPT);
|
AES_ENCRYPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AesCbcEncryptor::SetIv(const std::vector<uint8>& iv) {
|
bool AesCbcPkcs5Encryptor::SetIv(const std::vector<uint8>& iv) {
|
||||||
if (iv.size() != AES_BLOCK_SIZE) {
|
if (iv.size() != AES_BLOCK_SIZE) {
|
||||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||||
return false;
|
return false;
|
||||||
|
@ -195,11 +195,11 @@ bool AesCbcEncryptor::SetIv(const std::vector<uint8>& iv) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AesCbcDecryptor::AesCbcDecryptor() {}
|
AesCbcPkcs5Decryptor::AesCbcPkcs5Decryptor() {}
|
||||||
AesCbcDecryptor::~AesCbcDecryptor() {}
|
AesCbcPkcs5Decryptor::~AesCbcPkcs5Decryptor() {}
|
||||||
|
|
||||||
bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8>& key,
|
bool AesCbcPkcs5Decryptor::InitializeWithIv(const std::vector<uint8>& key,
|
||||||
const std::vector<uint8>& iv) {
|
const std::vector<uint8>& iv) {
|
||||||
if (!IsKeySizeValidForAes(key.size())) {
|
if (!IsKeySizeValidForAes(key.size())) {
|
||||||
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||||
return false;
|
return false;
|
||||||
|
@ -216,8 +216,8 @@ bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8>& key,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AesCbcDecryptor::Decrypt(const std::string& ciphertext,
|
bool AesCbcPkcs5Decryptor::Decrypt(const std::string& ciphertext,
|
||||||
std::string* plaintext) {
|
std::string* plaintext) {
|
||||||
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
|
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
|
||||||
LOG(ERROR) << "Expecting cipher text size to be multiple of "
|
LOG(ERROR) << "Expecting cipher text size to be multiple of "
|
||||||
<< AES_BLOCK_SIZE << ", got " << ciphertext.size();
|
<< AES_BLOCK_SIZE << ", got " << ciphertext.size();
|
||||||
|
@ -246,7 +246,226 @@ bool AesCbcDecryptor::Decrypt(const std::string& ciphertext,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AesCbcDecryptor::SetIv(const std::vector<uint8>& iv) {
|
bool AesCbcPkcs5Decryptor::SetIv(const std::vector<uint8>& iv) {
|
||||||
|
if (iv.size() != AES_BLOCK_SIZE) {
|
||||||
|
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
iv_ = iv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AesCbcCtsEncryptor::AesCbcCtsEncryptor() {}
|
||||||
|
AesCbcCtsEncryptor::~AesCbcCtsEncryptor() {}
|
||||||
|
|
||||||
|
bool AesCbcCtsEncryptor::InitializeWithIv(const std::vector<uint8>& key,
|
||||||
|
const std::vector<uint8>& iv) {
|
||||||
|
if (!IsKeySizeValidForAes(key.size())) {
|
||||||
|
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (iv.size() != AES_BLOCK_SIZE) {
|
||||||
|
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypt_key_.reset(new AES_KEY());
|
||||||
|
CHECK_EQ(AES_set_encrypt_key(&key[0], key.size() * 8, encrypt_key_.get()), 0);
|
||||||
|
|
||||||
|
iv_ = iv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AesCbcCtsEncryptor::Encrypt(const uint8* plaintext,
|
||||||
|
size_t size,
|
||||||
|
uint8* ciphertext) {
|
||||||
|
DCHECK(plaintext);
|
||||||
|
DCHECK(ciphertext);
|
||||||
|
|
||||||
|
if (size < AES_BLOCK_SIZE) {
|
||||||
|
// Don't have a full block, leave unencrypted.
|
||||||
|
memcpy(ciphertext, plaintext, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8> iv(iv_);
|
||||||
|
size_t residual_block_size = size % AES_BLOCK_SIZE;
|
||||||
|
size_t cbc_size = size - residual_block_size;
|
||||||
|
|
||||||
|
// Encrypt everything but the residual block using CBC.
|
||||||
|
AES_cbc_encrypt(plaintext,
|
||||||
|
ciphertext,
|
||||||
|
cbc_size,
|
||||||
|
encrypt_key_.get(),
|
||||||
|
&iv[0],
|
||||||
|
AES_ENCRYPT);
|
||||||
|
if (residual_block_size == 0) {
|
||||||
|
// No residual block. No need to do ciphertext stealing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero-pad the residual block and encrypt using CBC.
|
||||||
|
std::vector<uint8> residual_block(plaintext + size - residual_block_size,
|
||||||
|
plaintext + size);
|
||||||
|
residual_block.resize(AES_BLOCK_SIZE, 0);
|
||||||
|
AES_cbc_encrypt(&residual_block[0],
|
||||||
|
&residual_block[0],
|
||||||
|
AES_BLOCK_SIZE,
|
||||||
|
encrypt_key_.get(),
|
||||||
|
&iv[0],
|
||||||
|
AES_ENCRYPT);
|
||||||
|
|
||||||
|
// Replace the last full block with the zero-padded, encrypted residual block,
|
||||||
|
// and replace the residual block with the equivalent portion of the last full
|
||||||
|
// encrypted block. It may appear that some encrypted bits of the last full
|
||||||
|
// block are lost, but they are not, as they were used as the IV when
|
||||||
|
// encrypting the zero-padded residual block.
|
||||||
|
uint8* residual_ciphertext_block = ciphertext + size - residual_block_size;
|
||||||
|
memcpy(residual_ciphertext_block,
|
||||||
|
residual_ciphertext_block - AES_BLOCK_SIZE,
|
||||||
|
residual_block_size);
|
||||||
|
memcpy(residual_ciphertext_block - AES_BLOCK_SIZE,
|
||||||
|
residual_block.data(),
|
||||||
|
AES_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AesCbcCtsEncryptor::Encrypt(const std::vector<uint8>& plaintext,
|
||||||
|
std::vector<uint8>* ciphertext) {
|
||||||
|
DCHECK(ciphertext);
|
||||||
|
|
||||||
|
ciphertext->resize(plaintext.size(), 0);
|
||||||
|
if (plaintext.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
return Encrypt(plaintext.data(), plaintext.size(), &(*ciphertext)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AesCbcCtsEncryptor::SetIv(const std::vector<uint8>& iv) {
|
||||||
|
if (iv.size() != AES_BLOCK_SIZE) {
|
||||||
|
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
iv_ = iv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AesCbcCtsDecryptor::AesCbcCtsDecryptor() {}
|
||||||
|
AesCbcCtsDecryptor::~AesCbcCtsDecryptor() {}
|
||||||
|
|
||||||
|
bool AesCbcCtsDecryptor::InitializeWithIv(const std::vector<uint8>& key,
|
||||||
|
const std::vector<uint8>& iv) {
|
||||||
|
if (!IsKeySizeValidForAes(key.size())) {
|
||||||
|
LOG(ERROR) << "Invalid AES key size: " << key.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (iv.size() != AES_BLOCK_SIZE) {
|
||||||
|
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt_key_.reset(new AES_KEY());
|
||||||
|
CHECK_EQ(AES_set_decrypt_key(&key[0], key.size() * 8, decrypt_key_.get()), 0);
|
||||||
|
|
||||||
|
iv_ = iv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AesCbcCtsDecryptor::Decrypt(const uint8* ciphertext,
|
||||||
|
size_t size,
|
||||||
|
uint8* plaintext) {
|
||||||
|
DCHECK(ciphertext);
|
||||||
|
DCHECK(plaintext);
|
||||||
|
|
||||||
|
if (size < AES_BLOCK_SIZE) {
|
||||||
|
// Don't have a full block, leave unencrypted.
|
||||||
|
memcpy(plaintext, ciphertext, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8> iv(iv_);
|
||||||
|
size_t residual_block_size = size % AES_BLOCK_SIZE;
|
||||||
|
|
||||||
|
if (residual_block_size == 0) {
|
||||||
|
// No residual block. No need to do ciphertext stealing.
|
||||||
|
AES_cbc_encrypt(ciphertext,
|
||||||
|
plaintext,
|
||||||
|
size,
|
||||||
|
decrypt_key_.get(),
|
||||||
|
&iv[0],
|
||||||
|
AES_DECRYPT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AES-CBC decrypt everything up to the next-to-last full block.
|
||||||
|
size_t cbc_size = size - residual_block_size;
|
||||||
|
if (cbc_size > AES_BLOCK_SIZE) {
|
||||||
|
AES_cbc_encrypt(ciphertext,
|
||||||
|
plaintext,
|
||||||
|
cbc_size - AES_BLOCK_SIZE,
|
||||||
|
decrypt_key_.get(),
|
||||||
|
&iv[0],
|
||||||
|
AES_DECRYPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine what the last IV should be so that we can "skip ahead" in the
|
||||||
|
// CBC decryption.
|
||||||
|
std::vector<uint8> last_iv(ciphertext + size - residual_block_size,
|
||||||
|
ciphertext + size);
|
||||||
|
last_iv.resize(AES_BLOCK_SIZE, 0);
|
||||||
|
|
||||||
|
// Decrypt the next-to-last block using the IV determined above. This decrypts
|
||||||
|
// the residual block bits.
|
||||||
|
AES_cbc_encrypt(ciphertext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||||
|
plaintext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||||
|
AES_BLOCK_SIZE,
|
||||||
|
decrypt_key_.get(),
|
||||||
|
&last_iv[0],
|
||||||
|
AES_DECRYPT);
|
||||||
|
|
||||||
|
// Swap back the residual block bits and the next-to-last full block.
|
||||||
|
if (plaintext == ciphertext) {
|
||||||
|
uint8* ptr1 = plaintext + size - residual_block_size;
|
||||||
|
uint8* ptr2 = plaintext + size - residual_block_size - AES_BLOCK_SIZE;
|
||||||
|
for (size_t i = 0; i < residual_block_size; ++i) {
|
||||||
|
uint8 temp = *ptr1;
|
||||||
|
*ptr1 = *ptr2;
|
||||||
|
*ptr2 = temp;
|
||||||
|
++ptr1;
|
||||||
|
++ptr2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint8* residual_plaintext_block = plaintext + size - residual_block_size;
|
||||||
|
memcpy(residual_plaintext_block,
|
||||||
|
residual_plaintext_block - AES_BLOCK_SIZE,
|
||||||
|
residual_block_size);
|
||||||
|
memcpy(residual_plaintext_block - AES_BLOCK_SIZE,
|
||||||
|
ciphertext + size - residual_block_size,
|
||||||
|
residual_block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the last full block.
|
||||||
|
AES_cbc_encrypt(plaintext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||||
|
plaintext + size - residual_block_size - AES_BLOCK_SIZE,
|
||||||
|
AES_BLOCK_SIZE,
|
||||||
|
decrypt_key_.get(),
|
||||||
|
&iv[0],
|
||||||
|
AES_DECRYPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AesCbcCtsDecryptor::Decrypt(const std::vector<uint8>& ciphertext,
|
||||||
|
std::vector<uint8>* plaintext) {
|
||||||
|
DCHECK(plaintext);
|
||||||
|
|
||||||
|
plaintext->resize(ciphertext.size(), 0);
|
||||||
|
if (ciphertext.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
return Decrypt(ciphertext.data(), ciphertext.size(), &(*plaintext)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AesCbcCtsDecryptor::SetIv(const std::vector<uint8>& iv) {
|
||||||
if (iv.size() != AES_BLOCK_SIZE) {
|
if (iv.size() != AES_BLOCK_SIZE) {
|
||||||
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
LOG(ERROR) << "Invalid IV size: " << iv.size();
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -21,6 +21,7 @@ typedef struct aes_key_st AES_KEY;
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
// Class which implements AES-CTR counter-mode encryption/decryption.
|
||||||
class AesCtrEncryptor {
|
class AesCtrEncryptor {
|
||||||
public:
|
public:
|
||||||
AesCtrEncryptor();
|
AesCtrEncryptor();
|
||||||
|
@ -109,10 +110,12 @@ class AesCtrEncryptor {
|
||||||
DISALLOW_COPY_AND_ASSIGN(AesCtrEncryptor);
|
DISALLOW_COPY_AND_ASSIGN(AesCtrEncryptor);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AesCbcEncryptor {
|
// Class which implements AES-CBC (Cipher block chaining) encryption with
|
||||||
|
// PKCS#5 padding.
|
||||||
|
class AesCbcPkcs5Encryptor {
|
||||||
public:
|
public:
|
||||||
AesCbcEncryptor();
|
AesCbcPkcs5Encryptor();
|
||||||
~AesCbcEncryptor();
|
~AesCbcPkcs5Encryptor();
|
||||||
|
|
||||||
/// Initialize the encryptor with specified key and IV.
|
/// Initialize the encryptor with specified key and IV.
|
||||||
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||||
|
@ -135,13 +138,15 @@ class AesCbcEncryptor {
|
||||||
std::vector<uint8> iv_;
|
std::vector<uint8> iv_;
|
||||||
scoped_ptr<AES_KEY> encrypt_key_;
|
scoped_ptr<AES_KEY> encrypt_key_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AesCbcEncryptor);
|
DISALLOW_COPY_AND_ASSIGN(AesCbcPkcs5Encryptor);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AesCbcDecryptor {
|
// Class which implements AES-CBC (Cipher block chaining) decryption with
|
||||||
|
// PKCS#5 padding.
|
||||||
|
class AesCbcPkcs5Decryptor {
|
||||||
public:
|
public:
|
||||||
AesCbcDecryptor();
|
AesCbcPkcs5Decryptor();
|
||||||
~AesCbcDecryptor();
|
~AesCbcPkcs5Decryptor();
|
||||||
|
|
||||||
/// Initialize the decryptor with specified key and IV.
|
/// Initialize the decryptor with specified key and IV.
|
||||||
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||||
|
@ -165,7 +170,92 @@ class AesCbcDecryptor {
|
||||||
std::vector<uint8> iv_;
|
std::vector<uint8> iv_;
|
||||||
scoped_ptr<AES_KEY> decrypt_key_;
|
scoped_ptr<AES_KEY> decrypt_key_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AesCbcDecryptor);
|
DISALLOW_COPY_AND_ASSIGN(AesCbcPkcs5Decryptor);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class which implements AES-CBC (Cipher block chaining) encryption with
|
||||||
|
// Ciphertext stealing.
|
||||||
|
class AesCbcCtsEncryptor {
|
||||||
|
public:
|
||||||
|
AesCbcCtsEncryptor();
|
||||||
|
~AesCbcCtsEncryptor();
|
||||||
|
|
||||||
|
/// Initialize the encryptor with specified key and IV.
|
||||||
|
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||||
|
/// in AES spec.
|
||||||
|
/// @param iv should be 16 bytes in size.
|
||||||
|
/// @return true on successful initialization, false otherwise.
|
||||||
|
bool InitializeWithIv(const std::vector<uint8>& key,
|
||||||
|
const std::vector<uint8>& iv);
|
||||||
|
|
||||||
|
/// @param plaintext points to the data to be encrypted.
|
||||||
|
/// @param size is the number of bytes to be encrypted. If less than 16
|
||||||
|
/// bytes, it will be copied in the clear.
|
||||||
|
/// @param ciphertext should not be NULL. The buffer should be at least
|
||||||
|
/// @a size bytes in length.
|
||||||
|
void Encrypt(const uint8* plaintext,
|
||||||
|
size_t size,
|
||||||
|
uint8* ciphertext);
|
||||||
|
|
||||||
|
/// @param plaintext contains the data to be encrypted. If less than 16
|
||||||
|
/// bytes in size, it will be copied in the clear.
|
||||||
|
/// @param ciphertext should not be NULL. Caller retains ownership.
|
||||||
|
void Encrypt(const std::vector<uint8>& plaintext,
|
||||||
|
std::vector<uint8>* ciphertext);
|
||||||
|
|
||||||
|
/// @param iv is the initialization vector. Should be 16 bytes in size.
|
||||||
|
/// @return true if successful, false if the input is invalid.
|
||||||
|
bool SetIv(const std::vector<uint8>& iv);
|
||||||
|
|
||||||
|
const std::vector<uint8>& iv() const { return iv_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8> iv_;
|
||||||
|
scoped_ptr<AES_KEY> encrypt_key_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(AesCbcCtsEncryptor);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class which implements AES-CBC (Cipher block chaining) decryption with
|
||||||
|
// Ciphertext stealing.
|
||||||
|
class AesCbcCtsDecryptor {
|
||||||
|
public:
|
||||||
|
AesCbcCtsDecryptor();
|
||||||
|
~AesCbcCtsDecryptor();
|
||||||
|
|
||||||
|
/// Initialize the decryptor with specified key and IV.
|
||||||
|
/// @param key should be 128 bits or 192 bits or 256 bits in size as defined
|
||||||
|
/// in AES spec.
|
||||||
|
/// @param iv should be 16 bytes in size.
|
||||||
|
/// @return true on successful initialization, false otherwise.
|
||||||
|
bool InitializeWithIv(const std::vector<uint8>& key,
|
||||||
|
const std::vector<uint8>& iv);
|
||||||
|
|
||||||
|
/// @param ciphertext points to the data to be decrypted.
|
||||||
|
/// @param size is the number of bytes to be decrypted. If less than 16
|
||||||
|
/// bytes, it will be copied in the clear.
|
||||||
|
/// @param plaintext should not be NULL. The buffer should be at least
|
||||||
|
/// @a size bytes in length.
|
||||||
|
void Decrypt(const uint8* ciphertext,
|
||||||
|
size_t size,
|
||||||
|
uint8* plaintext);
|
||||||
|
|
||||||
|
/// @param ciphertext contains the data to be decrypted. If less than 16
|
||||||
|
/// bytes in size, it will be copied in the clear.
|
||||||
|
/// @param plaintext should not be NULL. Caller retains ownership.
|
||||||
|
void Decrypt(const std::vector<uint8>& ciphertext,
|
||||||
|
std::vector<uint8>* plaintext);
|
||||||
|
|
||||||
|
/// @return true if successful, false if the input is invalid.
|
||||||
|
bool SetIv(const std::vector<uint8>& iv);
|
||||||
|
|
||||||
|
const std::vector<uint8>& iv() const { return iv_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8> iv_;
|
||||||
|
scoped_ptr<AES_KEY> decrypt_key_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(AesCbcCtsDecryptor);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -17,11 +17,11 @@ const uint32 kAesBlockSize = 16;
|
||||||
|
|
||||||
// From NIST SP 800-38a test case: - F.5.1 CTR-AES128.Encrypt
|
// From NIST SP 800-38a test case: - F.5.1 CTR-AES128.Encrypt
|
||||||
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||||
const uint8 kAesCtrKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
const uint8 kAesKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||||
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
|
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
|
||||||
|
|
||||||
const uint8 kAesCtrIv[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
const uint8 kAesIv[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
|
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
|
||||||
|
|
||||||
const uint8 kAesCtrPlaintext[] = {
|
const uint8 kAesCtrPlaintext[] = {
|
||||||
// Block #1
|
// Block #1
|
||||||
|
@ -136,8 +136,8 @@ namespace media {
|
||||||
class AesCtrEncryptorTest : public testing::Test {
|
class AesCtrEncryptorTest : public testing::Test {
|
||||||
public:
|
public:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
key_.assign(kAesCtrKey, kAesCtrKey + arraysize(kAesCtrKey));
|
key_.assign(kAesKey, kAesKey + arraysize(kAesKey));
|
||||||
iv_.assign(kAesCtrIv, kAesCtrIv + arraysize(kAesCtrIv));
|
iv_.assign(kAesIv, kAesIv + arraysize(kAesIv));
|
||||||
plaintext_.assign(kAesCtrPlaintext,
|
plaintext_.assign(kAesCtrPlaintext,
|
||||||
kAesCtrPlaintext + arraysize(kAesCtrPlaintext));
|
kAesCtrPlaintext + arraysize(kAesCtrPlaintext));
|
||||||
ciphertext_.assign(kAesCtrCiphertext,
|
ciphertext_.assign(kAesCtrCiphertext,
|
||||||
|
@ -298,13 +298,13 @@ INSTANTIATE_TEST_CASE_P(IvTestCases,
|
||||||
AesCtrEncryptorIvTest,
|
AesCtrEncryptorIvTest,
|
||||||
::testing::ValuesIn(kIvTestCases));
|
::testing::ValuesIn(kIvTestCases));
|
||||||
|
|
||||||
class AesCbcEncryptorTestEncryptionDecryption : public testing::Test {
|
class AesCbcPkcs5EncryptorTestEncryptionDecryption : public testing::Test {
|
||||||
public:
|
public:
|
||||||
void TestEncryptionDecryption(const std::vector<uint8>& key,
|
void TestEncryptionDecryption(const std::vector<uint8>& key,
|
||||||
const std::vector<uint8>& iv,
|
const std::vector<uint8>& iv,
|
||||||
const std::string& plaintext,
|
const std::string& plaintext,
|
||||||
const std::string& expected_ciphertext_hex) {
|
const std::string& expected_ciphertext_hex) {
|
||||||
AesCbcEncryptor encryptor;
|
AesCbcPkcs5Encryptor encryptor;
|
||||||
EXPECT_TRUE(encryptor.InitializeWithIv(key, iv));
|
EXPECT_TRUE(encryptor.InitializeWithIv(key, iv));
|
||||||
|
|
||||||
std::string ciphertext;
|
std::string ciphertext;
|
||||||
|
@ -312,7 +312,7 @@ class AesCbcEncryptorTestEncryptionDecryption : public testing::Test {
|
||||||
EXPECT_EQ(expected_ciphertext_hex,
|
EXPECT_EQ(expected_ciphertext_hex,
|
||||||
base::HexEncode(ciphertext.data(), ciphertext.size()));
|
base::HexEncode(ciphertext.data(), ciphertext.size()));
|
||||||
|
|
||||||
AesCbcDecryptor decryptor;
|
AesCbcPkcs5Decryptor decryptor;
|
||||||
ASSERT_TRUE(decryptor.InitializeWithIv(key, iv));
|
ASSERT_TRUE(decryptor.InitializeWithIv(key, iv));
|
||||||
|
|
||||||
std::string decrypted;
|
std::string decrypted;
|
||||||
|
@ -321,7 +321,7 @@ class AesCbcEncryptorTestEncryptionDecryption : public testing::Test {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTestEncryptionDecryption, EncryptAES256CBC) {
|
TEST_F(AesCbcPkcs5EncryptorTestEncryptionDecryption, EncryptAES256CBC) {
|
||||||
// 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 kAesCbcKey[] = {
|
static const uint8 kAesCbcKey[] = {
|
||||||
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae,
|
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae,
|
||||||
|
@ -370,7 +370,7 @@ TEST_F(AesCbcEncryptorTestEncryptionDecryption, EncryptAES256CBC) {
|
||||||
TestEncryptionDecryption(key, iv, plaintext, expected_ciphertext_hex);
|
TestEncryptionDecryption(key, iv, plaintext, expected_ciphertext_hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTestEncryptionDecryption, EncryptAES128CBCRegression) {
|
TEST_F(AesCbcPkcs5EncryptorTestEncryptionDecryption, EncryptAES128CBCRegression) {
|
||||||
const std::string kKey = "128=SixteenBytes";
|
const std::string kKey = "128=SixteenBytes";
|
||||||
const std::string kIv = "Sweet Sixteen IV";
|
const std::string kIv = "Sweet Sixteen IV";
|
||||||
const std::string kPlaintext =
|
const std::string kPlaintext =
|
||||||
|
@ -385,7 +385,7 @@ TEST_F(AesCbcEncryptorTestEncryptionDecryption, EncryptAES128CBCRegression) {
|
||||||
TestEncryptionDecryption(key, iv, kPlaintext, kExpectedCiphertextHex);
|
TestEncryptionDecryption(key, iv, kPlaintext, kExpectedCiphertextHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTestEncryptionDecryption, EncryptAES192CBCRegression) {
|
TEST_F(AesCbcPkcs5EncryptorTestEncryptionDecryption, EncryptAES192CBCRegression) {
|
||||||
const std::string kKey = "192bitsIsTwentyFourByte!";
|
const std::string kKey = "192bitsIsTwentyFourByte!";
|
||||||
const std::string kIv = "Sweet Sixteen IV";
|
const std::string kIv = "Sweet Sixteen IV";
|
||||||
const std::string kPlaintext = "Small text";
|
const std::string kPlaintext = "Small text";
|
||||||
|
@ -397,7 +397,7 @@ TEST_F(AesCbcEncryptorTestEncryptionDecryption, EncryptAES192CBCRegression) {
|
||||||
TestEncryptionDecryption(key, iv, kPlaintext, kExpectedCiphertextHex);
|
TestEncryptionDecryption(key, iv, kPlaintext, kExpectedCiphertextHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AesCbcEncryptorTest : public testing::Test {
|
class AesCbcPkcs5EncryptorTest : public testing::Test {
|
||||||
public:
|
public:
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
const std::string kKey = "128=SixteenBytes";
|
const std::string kKey = "128=SixteenBytes";
|
||||||
|
@ -411,18 +411,18 @@ class AesCbcEncryptorTest : public testing::Test {
|
||||||
std::vector<uint8> iv_;
|
std::vector<uint8> iv_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTest, UnsupportedKeySize) {
|
TEST_F(AesCbcPkcs5EncryptorTest, UnsupportedKeySize) {
|
||||||
AesCbcEncryptor encryptor;
|
AesCbcPkcs5Encryptor encryptor;
|
||||||
EXPECT_FALSE(encryptor.InitializeWithIv(std::vector<uint8>(15, 0), iv_));
|
EXPECT_FALSE(encryptor.InitializeWithIv(std::vector<uint8>(15, 0), iv_));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTest, UnsupportedIvSize) {
|
TEST_F(AesCbcPkcs5EncryptorTest, UnsupportedIvSize) {
|
||||||
AesCbcEncryptor encryptor;
|
AesCbcPkcs5Encryptor encryptor;
|
||||||
EXPECT_FALSE(encryptor.InitializeWithIv(key_, std::vector<uint8>(14, 0)));
|
EXPECT_FALSE(encryptor.InitializeWithIv(key_, std::vector<uint8>(14, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTest, EmptyEncrypt) {
|
TEST_F(AesCbcPkcs5EncryptorTest, EmptyEncrypt) {
|
||||||
AesCbcEncryptor encryptor;
|
AesCbcPkcs5Encryptor encryptor;
|
||||||
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
ASSERT_TRUE(encryptor.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
std::string ciphertext;
|
std::string ciphertext;
|
||||||
|
@ -432,13 +432,119 @@ TEST_F(AesCbcEncryptorTest, EmptyEncrypt) {
|
||||||
base::HexEncode(ciphertext.data(), ciphertext.size()));
|
base::HexEncode(ciphertext.data(), ciphertext.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AesCbcEncryptorTest, CipherTextNotMultipleOfBlockSize) {
|
TEST_F(AesCbcPkcs5EncryptorTest, CipherTextNotMultipleOfBlockSize) {
|
||||||
AesCbcDecryptor decryptor;
|
AesCbcPkcs5Decryptor decryptor;
|
||||||
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
ASSERT_TRUE(decryptor.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
std::string plaintext;
|
std::string plaintext;
|
||||||
EXPECT_FALSE(decryptor.Decrypt("1", &plaintext));
|
EXPECT_FALSE(decryptor.Decrypt("1", &plaintext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AesCbcCtsEncryptorDecryptorTest : public testing::Test {
|
||||||
|
public:
|
||||||
|
virtual void SetUp() {
|
||||||
|
key_.assign(kAesKey, kAesKey + arraysize(kAesKey));
|
||||||
|
iv_.assign(kAesIv, kAesIv + arraysize(kAesIv));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestEncryptDecryptSeparateBuffers(
|
||||||
|
const std::vector<uint8>& plaintext,
|
||||||
|
const std::vector<uint8>& expected_ciphertext) {
|
||||||
|
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_));
|
||||||
|
ASSERT_TRUE(decryptor_.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
|
std::vector<uint8> encrypted;
|
||||||
|
encryptor_.Encrypt(plaintext, &encrypted);
|
||||||
|
EXPECT_EQ(expected_ciphertext, encrypted);
|
||||||
|
|
||||||
|
std::vector<uint8> decrypted;
|
||||||
|
decryptor_.Decrypt(encrypted, &decrypted);
|
||||||
|
EXPECT_EQ(plaintext, decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestEncryptDecryptInPlace(
|
||||||
|
const std::vector<uint8>& plaintext,
|
||||||
|
const std::vector<uint8>& expected_ciphertext) {
|
||||||
|
ASSERT_TRUE(encryptor_.InitializeWithIv(key_, iv_));
|
||||||
|
ASSERT_TRUE(decryptor_.InitializeWithIv(key_, iv_));
|
||||||
|
|
||||||
|
std::vector<uint8> buffer(plaintext);
|
||||||
|
encryptor_.Encrypt(buffer, &buffer);
|
||||||
|
EXPECT_EQ(expected_ciphertext, buffer);
|
||||||
|
decryptor_.Decrypt(buffer, &buffer);
|
||||||
|
EXPECT_EQ(plaintext, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<uint8> key_;
|
||||||
|
std::vector<uint8> iv_;
|
||||||
|
AesCbcCtsEncryptor encryptor_;
|
||||||
|
AesCbcCtsDecryptor decryptor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AesCbcCtsEncryptorDecryptorTest, TestWithResidualBytes) {
|
||||||
|
std::vector<uint8> plaintext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes(
|
||||||
|
"e0818f2dc7caaa9edf09285a0c1fca98d39e9b08a47ab6911c4bbdf27d94"
|
||||||
|
"f917cdffc9ebb307141f23b0d3921e0ed7f86eb09381286f8e7a4f",
|
||||||
|
&plaintext));
|
||||||
|
|
||||||
|
std::vector<uint8> ciphertext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes(
|
||||||
|
"b40a0b8704c74e22e8030cad6f272b34ace54cc7c9c64b2018bbcf23df018"
|
||||||
|
"39b14899441cf74a9fb2f2b229a609146f31be8e8a826eb6e857e",
|
||||||
|
&ciphertext));
|
||||||
|
|
||||||
|
TestEncryptDecryptSeparateBuffers(plaintext, ciphertext);
|
||||||
|
TestEncryptDecryptInPlace(plaintext, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AesCbcCtsEncryptorDecryptorTest, TestEvenBlocks) {
|
||||||
|
std::vector<uint8> plaintext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes(
|
||||||
|
"3f593e7a204a5e70f2814dca05aa49d36f2daddc9a24e0515802c539efc3"
|
||||||
|
"1094b3ad6c26d6f5c0e387545ce6a4c2c14d",
|
||||||
|
&plaintext));
|
||||||
|
|
||||||
|
std::vector<uint8> ciphertext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes(
|
||||||
|
"5f32cd0504b27b25ee04090d88d37d340c9c0a9fa50b05358b98fad4302ea"
|
||||||
|
"480148d8aa091f4e7d186a7223df153f6f7",
|
||||||
|
&ciphertext));
|
||||||
|
|
||||||
|
TestEncryptDecryptSeparateBuffers(plaintext, ciphertext);
|
||||||
|
TestEncryptDecryptInPlace(plaintext, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AesCbcCtsEncryptorDecryptorTest, TestOneBlockAndAHalf) {
|
||||||
|
std::vector<uint8> plaintext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes(
|
||||||
|
"3f593e7a204a5e70f2814dca05aa49d36f2daddc9a4302ea",
|
||||||
|
&plaintext));
|
||||||
|
|
||||||
|
std::vector<uint8> ciphertext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes(
|
||||||
|
"623fc113fe02ce85628deb58d652c6995f32cd0504b27b25",
|
||||||
|
&ciphertext));
|
||||||
|
|
||||||
|
TestEncryptDecryptSeparateBuffers(plaintext, ciphertext);
|
||||||
|
TestEncryptDecryptInPlace(plaintext, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AesCbcCtsEncryptorDecryptorTest, TestZeroEncryptedBlocks) {
|
||||||
|
std::vector<uint8> plaintext;
|
||||||
|
ASSERT_TRUE(base::HexStringToBytes("3f593e7a204a5e70f2", &plaintext));
|
||||||
|
|
||||||
|
TestEncryptDecryptSeparateBuffers(plaintext, plaintext);
|
||||||
|
TestEncryptDecryptInPlace(plaintext, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AesCbcCtsEncryptorDecryptorTest, TestZeroBytes) {
|
||||||
|
std::vector<uint8> plaintext;
|
||||||
|
|
||||||
|
TestEncryptDecryptSeparateBuffers(plaintext, plaintext);
|
||||||
|
TestEncryptDecryptInPlace(plaintext, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -19,7 +19,7 @@ RequestSigner::RequestSigner(const std::string& signer_name)
|
||||||
RequestSigner::~RequestSigner() {}
|
RequestSigner::~RequestSigner() {}
|
||||||
|
|
||||||
AesRequestSigner::AesRequestSigner(const std::string& signer_name,
|
AesRequestSigner::AesRequestSigner(const std::string& signer_name,
|
||||||
scoped_ptr<AesCbcEncryptor> encryptor)
|
scoped_ptr<AesCbcPkcs5Encryptor> encryptor)
|
||||||
: RequestSigner(signer_name), aes_cbc_encryptor_(encryptor.Pass()) {
|
: RequestSigner(signer_name), aes_cbc_encryptor_(encryptor.Pass()) {
|
||||||
DCHECK(aes_cbc_encryptor_);
|
DCHECK(aes_cbc_encryptor_);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ AesRequestSigner* AesRequestSigner::CreateSigner(const std::string& signer_name,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_ptr<AesCbcEncryptor> encryptor(new AesCbcEncryptor());
|
scoped_ptr<AesCbcPkcs5Encryptor> encryptor(new AesCbcPkcs5Encryptor());
|
||||||
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());
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
class AesCbcEncryptor;
|
class AesCbcPkcs5Encryptor;
|
||||||
class RsaPrivateKey;
|
class RsaPrivateKey;
|
||||||
|
|
||||||
/// Abstract class used for signature generation.
|
/// Abstract class used for signature generation.
|
||||||
|
@ -57,9 +57,9 @@ class AesRequestSigner : public RequestSigner {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AesRequestSigner(const std::string& signer_name,
|
AesRequestSigner(const std::string& signer_name,
|
||||||
scoped_ptr<AesCbcEncryptor> encryptor);
|
scoped_ptr<AesCbcPkcs5Encryptor> encryptor);
|
||||||
|
|
||||||
scoped_ptr<AesCbcEncryptor> aes_cbc_encryptor_;
|
scoped_ptr<AesCbcPkcs5Encryptor> aes_cbc_encryptor_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AesRequestSigner);
|
DISALLOW_COPY_AND_ASSIGN(AesRequestSigner);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue