7 #include <packager/media/base/aes_encryptor.h>
9 #include <absl/log/check.h>
10 #include <absl/log/log.h>
12 #include <packager/macros/crypto.h>
17 bool Increment64(uint8_t* counter) {
19 for (
int i = 7; i >= 0; --i) {
20 if (++counter[i] != 0)
33 AesCtrEncryptor::AesCtrEncryptor()
34 : AesCryptor(kDontUseConstantIv),
36 encrypted_counter_(AES_BLOCK_SIZE, 0) {}
38 AesCtrEncryptor::~AesCtrEncryptor() {}
40 bool AesCtrEncryptor::InitializeWithIv(
const std::vector<uint8_t>& key,
41 const std::vector<uint8_t>& iv) {
42 if (!SetupCipher(key.size(), kCtrMode)) {
46 if (mbedtls_cipher_setkey(&cipher_ctx_, key.data(),
47 static_cast<int>(8 * key.size()),
48 MBEDTLS_ENCRYPT) != 0) {
49 LOG(ERROR) <<
"Failed to set CTR encryption key";
56 bool AesCtrEncryptor::CryptInternal(
const uint8_t* plaintext,
57 size_t plaintext_size,
59 size_t* ciphertext_size) {
64 if (*ciphertext_size < plaintext_size) {
65 LOG(ERROR) <<
"Expecting output size of at least " << plaintext_size
69 *ciphertext_size = plaintext_size;
71 for (
size_t i = 0; i < plaintext_size; ++i) {
72 if (block_offset_ == 0) {
73 size_t ignored_output_size;
75 mbedtls_cipher_crypt(&cipher_ctx_, NULL, 0,
76 &counter_[0], AES_BLOCK_SIZE,
77 &encrypted_counter_[0], &ignored_output_size),
85 Increment64(&counter_[8]);
87 ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
88 block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
93 void AesCtrEncryptor::SetIvInternal() {
96 counter_.resize(AES_BLOCK_SIZE, 0);
99 AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme)
103 ConstantIvFlag constant_iv_flag)
104 :
AesCryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
105 if (padding_scheme_ != kNoPadding) {
106 CHECK_EQ(constant_iv_flag, kUseConstantIv)
107 <<
"non-constant iv (cipher block chain across calls) only makes sense "
108 "if the padding_scheme is kNoPadding.";
112 AesCbcEncryptor::~AesCbcEncryptor() {}
115 const std::vector<uint8_t>& iv) {
116 if (!SetupCipher(key.size(), kCbcMode)) {
120 if (mbedtls_cipher_setkey(&cipher_ctx_, key.data(),
121 static_cast<int>(8 * key.size()),
122 MBEDTLS_ENCRYPT) != 0) {
123 LOG(ERROR) <<
"Failed to set CBC encryption key";
130 size_t AesCbcEncryptor::RequiredOutputSize(
size_t plaintext_size) {
131 return plaintext_size + NumPaddingBytes(plaintext_size);
134 bool AesCbcEncryptor::CryptInternal(
const uint8_t* plaintext,
135 size_t plaintext_size,
137 size_t* ciphertext_size) {
138 const size_t residual_block_size = plaintext_size % AES_BLOCK_SIZE;
139 const size_t num_padding_bytes = NumPaddingBytes(plaintext_size);
140 const size_t required_ciphertext_size = RequiredOutputSize(plaintext_size);
142 if (*ciphertext_size < required_ciphertext_size) {
143 LOG(ERROR) <<
"Expecting output size of at least "
144 << required_ciphertext_size <<
" bytes.";
147 *ciphertext_size = required_ciphertext_size;
150 const size_t cbc_size = plaintext_size - residual_block_size;
152 CbcEncryptBlocks(plaintext, cbc_size, ciphertext, internal_iv_.data());
153 }
else if (padding_scheme_ == kCtsPadding) {
155 memcpy(ciphertext, plaintext, plaintext_size);
158 if (residual_block_size == 0 && padding_scheme_ != kPkcs5Padding) {
163 if (padding_scheme_ == kNoPadding) {
165 memcpy(ciphertext + cbc_size, plaintext + cbc_size, residual_block_size);
169 std::vector<uint8_t> residual_block(plaintext + cbc_size,
170 plaintext + plaintext_size);
171 DCHECK_EQ(residual_block.size(), residual_block_size);
172 uint8_t* residual_ciphertext_block = ciphertext + cbc_size;
174 if (padding_scheme_ == kPkcs5Padding) {
175 DCHECK_EQ(num_padding_bytes, AES_BLOCK_SIZE - residual_block_size);
178 residual_block.resize(AES_BLOCK_SIZE,
static_cast<char>(num_padding_bytes));
179 CbcEncryptBlocks(residual_block.data(), AES_BLOCK_SIZE,
180 residual_ciphertext_block, internal_iv_.data());
182 DCHECK_EQ(num_padding_bytes, 0u);
183 DCHECK_EQ(padding_scheme_, kCtsPadding);
186 residual_block.resize(AES_BLOCK_SIZE, 0);
187 CbcEncryptBlocks(residual_block.data(), AES_BLOCK_SIZE,
188 residual_block.data(), internal_iv_.data());
197 memcpy(residual_ciphertext_block,
198 residual_ciphertext_block - AES_BLOCK_SIZE, residual_block_size);
199 memcpy(residual_ciphertext_block - AES_BLOCK_SIZE, residual_block.data(),
205 void AesCbcEncryptor::SetIvInternal() {
207 internal_iv_.resize(AES_BLOCK_SIZE, 0);
210 size_t AesCbcEncryptor::NumPaddingBytes(
size_t size)
const {
211 return (padding_scheme_ == kPkcs5Padding)
212 ? (AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE))
216 void AesCbcEncryptor::CbcEncryptBlocks(
const uint8_t* plaintext,
217 size_t plaintext_size,
220 CHECK_EQ(plaintext_size % AES_BLOCK_SIZE, 0u);
222 size_t output_size = 0;
223 CHECK_EQ(mbedtls_cipher_crypt(&cipher_ctx_,
iv, AES_BLOCK_SIZE, plaintext,
224 plaintext_size, ciphertext, &output_size),
227 CHECK_EQ(output_size % AES_BLOCK_SIZE, 0u);
228 CHECK_GT(output_size, 0u);
230 uint8_t* last_block = ciphertext + output_size - AES_BLOCK_SIZE;
231 memcpy(
iv, last_block, AES_BLOCK_SIZE);
All the methods that are virtual are virtual for mocking.