7#include <packager/media/base/aes_encryptor.h>
14#include <absl/log/check.h>
15#include <absl/log/log.h>
16#include <mbedtls/cipher.h>
18#include <packager/macros/crypto.h>
19#include <packager/media/base/aes_cryptor.h>
24bool Increment64(uint8_t* counter) {
26 for (
int i = 7; i >= 0; --i) {
27 if (++counter[i] != 0)
40AesCtrEncryptor::AesCtrEncryptor()
41 : AesCryptor(kDontUseConstantIv),
43 encrypted_counter_(AES_BLOCK_SIZE, 0) {}
45AesCtrEncryptor::~AesCtrEncryptor() {}
47bool AesCtrEncryptor::InitializeWithIv(
const std::vector<uint8_t>& key,
48 const std::vector<uint8_t>& iv) {
49 if (!SetupCipher(key.size(), kCtrMode)) {
53 if (mbedtls_cipher_setkey(&cipher_ctx_, key.data(),
54 static_cast<int>(8 * key.size()),
55 MBEDTLS_ENCRYPT) != 0) {
56 LOG(ERROR) <<
"Failed to set CTR encryption key";
63bool AesCtrEncryptor::CryptInternal(
const uint8_t* plaintext,
64 size_t plaintext_size,
66 size_t* ciphertext_size) {
71 if (*ciphertext_size < plaintext_size) {
72 LOG(ERROR) <<
"Expecting output size of at least " << plaintext_size
76 *ciphertext_size = plaintext_size;
78 for (
size_t i = 0; i < plaintext_size; ++i) {
79 if (block_offset_ == 0) {
80 size_t ignored_output_size;
82 mbedtls_cipher_crypt(&cipher_ctx_, NULL, 0,
83 &counter_[0], AES_BLOCK_SIZE,
84 &encrypted_counter_[0], &ignored_output_size),
92 Increment64(&counter_[8]);
94 ciphertext[i] = plaintext[i] ^ encrypted_counter_[block_offset_];
95 block_offset_ = (block_offset_ + 1) % AES_BLOCK_SIZE;
100void AesCtrEncryptor::SetIvInternal() {
103 counter_.resize(AES_BLOCK_SIZE, 0);
106AesCbcEncryptor::AesCbcEncryptor(CbcPaddingScheme padding_scheme)
110 ConstantIvFlag constant_iv_flag)
111 :
AesCryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
112 if (padding_scheme_ != kNoPadding) {
113 CHECK_EQ(constant_iv_flag, kUseConstantIv)
114 <<
"non-constant iv (cipher block chain across calls) only makes sense "
115 "if the padding_scheme is kNoPadding.";
119AesCbcEncryptor::~AesCbcEncryptor() {}
122 const std::vector<uint8_t>& iv) {
123 if (!SetupCipher(key.size(), kCbcMode)) {
127 if (mbedtls_cipher_setkey(&cipher_ctx_, key.data(),
128 static_cast<int>(8 * key.size()),
129 MBEDTLS_ENCRYPT) != 0) {
130 LOG(ERROR) <<
"Failed to set CBC encryption key";
137size_t AesCbcEncryptor::RequiredOutputSize(
size_t plaintext_size) {
138 return plaintext_size + NumPaddingBytes(plaintext_size);
141bool AesCbcEncryptor::CryptInternal(
const uint8_t* plaintext,
142 size_t plaintext_size,
144 size_t* ciphertext_size) {
145 const size_t residual_block_size = plaintext_size % AES_BLOCK_SIZE;
146 const size_t num_padding_bytes = NumPaddingBytes(plaintext_size);
147 const size_t required_ciphertext_size = RequiredOutputSize(plaintext_size);
149 if (*ciphertext_size < required_ciphertext_size) {
150 LOG(ERROR) <<
"Expecting output size of at least "
151 << required_ciphertext_size <<
" bytes.";
154 *ciphertext_size = required_ciphertext_size;
157 const size_t cbc_size = plaintext_size - residual_block_size;
159 CbcEncryptBlocks(plaintext, cbc_size, ciphertext, internal_iv_.data());
160 }
else if (padding_scheme_ == kCtsPadding) {
162 memcpy(ciphertext, plaintext, plaintext_size);
165 if (residual_block_size == 0 && padding_scheme_ != kPkcs5Padding) {
170 if (padding_scheme_ == kNoPadding) {
172 memcpy(ciphertext + cbc_size, plaintext + cbc_size, residual_block_size);
176 std::vector<uint8_t> residual_block(plaintext + cbc_size,
177 plaintext + plaintext_size);
178 DCHECK_EQ(residual_block.size(), residual_block_size);
179 uint8_t* residual_ciphertext_block = ciphertext + cbc_size;
181 if (padding_scheme_ == kPkcs5Padding) {
182 DCHECK_EQ(num_padding_bytes, AES_BLOCK_SIZE - residual_block_size);
185 residual_block.resize(AES_BLOCK_SIZE,
static_cast<char>(num_padding_bytes));
186 CbcEncryptBlocks(residual_block.data(), AES_BLOCK_SIZE,
187 residual_ciphertext_block, internal_iv_.data());
189 DCHECK_EQ(num_padding_bytes, 0u);
190 DCHECK_EQ(padding_scheme_, kCtsPadding);
193 residual_block.resize(AES_BLOCK_SIZE, 0);
194 CbcEncryptBlocks(residual_block.data(), AES_BLOCK_SIZE,
195 residual_block.data(), internal_iv_.data());
204 memcpy(residual_ciphertext_block,
205 residual_ciphertext_block - AES_BLOCK_SIZE, residual_block_size);
206 memcpy(residual_ciphertext_block - AES_BLOCK_SIZE, residual_block.data(),
212void AesCbcEncryptor::SetIvInternal() {
214 internal_iv_.resize(AES_BLOCK_SIZE, 0);
217size_t AesCbcEncryptor::NumPaddingBytes(
size_t size)
const {
218 return (padding_scheme_ == kPkcs5Padding)
219 ? (AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE))
223void AesCbcEncryptor::CbcEncryptBlocks(
const uint8_t* plaintext,
224 size_t plaintext_size,
227 CHECK_EQ(plaintext_size % AES_BLOCK_SIZE, 0u);
229 size_t output_size = 0;
230 CHECK_EQ(mbedtls_cipher_crypt(&cipher_ctx_,
iv, AES_BLOCK_SIZE, plaintext,
231 plaintext_size, ciphertext, &output_size),
234 CHECK_EQ(output_size % AES_BLOCK_SIZE, 0u);
235 CHECK_GT(output_size, 0u);
237 uint8_t* last_block = ciphertext + output_size - AES_BLOCK_SIZE;
238 memcpy(
iv, last_block, AES_BLOCK_SIZE);
All the methods that are virtual are virtual for mocking.