7 #include "packager/media/base/aes_encryptor.h"
9 #include <openssl/aes.h>
11 #include "packager/base/logging.h"
16 bool Increment64(uint8_t* counter) {
18 for (
int i = 7; i >= 0; --i)
19 if (++counter[i] != 0)
26 bool IsIvSizeValid(
size_t iv_size) {
return iv_size == 8 || iv_size == 16; }
29 bool IsKeySizeValidForAes(
size_t key_size) {
30 return key_size == 16 || key_size == 24 || key_size == 32;
35 namespace edash_packager {
38 AesEncryptor::AesEncryptor() {}
39 AesEncryptor::~AesEncryptor() {}
42 const std::vector<uint8_t>& iv) {
43 if (!IsKeySizeValidForAes(key.size())) {
44 LOG(ERROR) <<
"Invalid AES key size: " << key.size();
48 CHECK_EQ(AES_set_encrypt_key(key.data(), key.size() * 8, mutable_aes_key()),
53 AesCtrEncryptor::AesCtrEncryptor()
55 encrypted_counter_(AES_BLOCK_SIZE, 0),
56 counter_overflow_(false) {}
58 AesCtrEncryptor::~AesCtrEncryptor() {}
69 if (
iv().size() == 8) {
71 Increment64(&counter_[0]);
73 counter_.resize(AES_BLOCK_SIZE, 0);
75 DCHECK_EQ(16u,
iv().size());
83 if (counter_overflow_)
84 Increment64(&counter_[0]);
87 counter_overflow_ =
false;
91 if (!IsIvSizeValid(iv.size())) {
92 LOG(ERROR) <<
"Invalid IV size: " << iv.size();
99 counter_.resize(AES_BLOCK_SIZE, 0);
103 bool AesCtrEncryptor::CryptInternal(
const uint8_t* plaintext,
104 size_t plaintext_size,
106 size_t* ciphertext_size) {
112 if (*ciphertext_size < plaintext_size) {
113 LOG(ERROR) <<
"Expecting output size of at least " << plaintext_size
117 *ciphertext_size = plaintext_size;
119 for (
size_t i = 0; i < plaintext_size; ++i) {
120 if (block_offset_ == 0) {
121 AES_encrypt(&counter_[0], &encrypted_counter_[0], aes_key());
127 if (Increment64(&counter_[8]))
128 counter_overflow_ =
true;
130 ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
131 block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
137 bool chain_across_calls)
138 : padding_scheme_(padding_scheme),
139 chain_across_calls_(chain_across_calls) {
140 if (padding_scheme_ != kNoPadding) {
141 CHECK(!chain_across_calls) <<
"cipher block chain across calls only makes "
142 "sense if the padding_scheme is kNoPadding.";
145 AesCbcEncryptor::~AesCbcEncryptor() {}
158 if (iv.size() != AES_BLOCK_SIZE) {
159 LOG(ERROR) <<
"Invalid IV size: " << iv.size();
167 bool AesCbcEncryptor::CryptInternal(
const uint8_t* plaintext,
168 size_t plaintext_size,
170 size_t* ciphertext_size) {
173 const size_t residual_block_size = plaintext_size % AES_BLOCK_SIZE;
174 if (padding_scheme_ == kNoPadding && residual_block_size != 0) {
175 LOG(ERROR) <<
"Expecting input size to be multiple of " << AES_BLOCK_SIZE
176 <<
", got " << plaintext_size;
180 const size_t num_padding_bytes = NumPaddingBytes(plaintext_size);
181 const size_t required_ciphertext_size = plaintext_size + num_padding_bytes;
182 if (*ciphertext_size < required_ciphertext_size) {
183 LOG(ERROR) <<
"Expecting output size of at least "
184 << required_ciphertext_size <<
" bytes.";
187 *ciphertext_size = required_ciphertext_size;
190 const size_t cbc_size = plaintext_size - residual_block_size;
191 std::vector<uint8_t> local_iv(
iv());
193 AES_cbc_encrypt(plaintext, ciphertext, cbc_size, aes_key(), local_iv.data(),
195 }
else if (padding_scheme_ == kCtsPadding) {
197 memcpy(ciphertext, plaintext, plaintext_size);
200 if (residual_block_size == 0 && padding_scheme_ != kPkcs5Padding) {
201 if (chain_across_calls_)
206 DCHECK(!chain_across_calls_);
208 std::vector<uint8_t> residual_block(plaintext + cbc_size,
209 plaintext + plaintext_size);
210 DCHECK_EQ(residual_block.size(), residual_block_size);
211 uint8_t* residual_ciphertext_block = ciphertext + cbc_size;
213 if (padding_scheme_ == kPkcs5Padding) {
214 DCHECK_EQ(num_padding_bytes, AES_BLOCK_SIZE - residual_block_size);
217 residual_block.resize(AES_BLOCK_SIZE, static_cast<char>(num_padding_bytes));
218 AES_cbc_encrypt(residual_block.data(), residual_ciphertext_block,
219 AES_BLOCK_SIZE, aes_key(), local_iv.data(), AES_ENCRYPT);
221 DCHECK_EQ(num_padding_bytes, 0u);
222 DCHECK_EQ(padding_scheme_, kCtsPadding);
225 residual_block.resize(AES_BLOCK_SIZE, 0);
226 AES_cbc_encrypt(residual_block.data(), residual_block.data(),
227 AES_BLOCK_SIZE, aes_key(), local_iv.data(), AES_ENCRYPT);
234 memcpy(residual_ciphertext_block,
235 residual_ciphertext_block - AES_BLOCK_SIZE, residual_block_size);
236 memcpy(residual_ciphertext_block - AES_BLOCK_SIZE, residual_block.data(),
242 size_t AesCbcEncryptor::NumPaddingBytes(
size_t size)
const {
243 return (padding_scheme_ == kPkcs5Padding)
244 ? (AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE))