2023-12-01 17:32:19 +00:00
|
|
|
// Copyright 2016 Google LLC. All rights reserved.
|
2016-03-17 17:03:19 +00:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <packager/media/base/aes_decryptor.h>
|
2016-03-17 17:03:19 +00:00
|
|
|
|
2016-08-19 22:32:27 +00:00
|
|
|
#include <algorithm>
|
2016-03-17 17:03:19 +00:00
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <absl/log/check.h>
|
|
|
|
#include <absl/log/log.h>
|
2016-03-17 17:03:19 +00:00
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <packager/macros/crypto.h>
|
2016-03-17 17:03:19 +00:00
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
namespace shaka {
|
2016-03-17 17:03:19 +00:00
|
|
|
namespace media {
|
|
|
|
|
2016-04-13 17:52:41 +00:00
|
|
|
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme)
|
|
|
|
: AesCbcDecryptor(padding_scheme, kDontUseConstantIv) {}
|
|
|
|
|
2016-03-25 18:02:43 +00:00
|
|
|
AesCbcDecryptor::AesCbcDecryptor(CbcPaddingScheme padding_scheme,
|
2016-04-13 17:52:41 +00:00
|
|
|
ConstantIvFlag constant_iv_flag)
|
|
|
|
: AesCryptor(constant_iv_flag), padding_scheme_(padding_scheme) {
|
2016-03-25 18:02:43 +00:00
|
|
|
if (padding_scheme_ != kNoPadding) {
|
2016-04-13 17:52:41 +00:00
|
|
|
CHECK_EQ(constant_iv_flag, kUseConstantIv)
|
|
|
|
<< "non-constant iv (cipher block chain across calls) only makes sense "
|
|
|
|
"if the padding_scheme is kNoPadding.";
|
2016-03-25 18:02:43 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-06 00:19:16 +00:00
|
|
|
|
2016-03-25 18:02:43 +00:00
|
|
|
AesCbcDecryptor::~AesCbcDecryptor() {}
|
2016-03-17 17:03:19 +00:00
|
|
|
|
2016-03-25 18:02:43 +00:00
|
|
|
bool AesCbcDecryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
|
|
|
const std::vector<uint8_t>& iv) {
|
2023-12-01 17:32:19 +00:00
|
|
|
if (!SetupCipher(key.size(), kCbcMode)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mbedtls_cipher_setkey(&cipher_ctx_, key.data(),
|
|
|
|
static_cast<int>(8 * key.size()),
|
|
|
|
MBEDTLS_DECRYPT) != 0) {
|
|
|
|
LOG(ERROR) << "Failed to set CBC decryption key";
|
2016-03-17 17:03:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-25 18:02:43 +00:00
|
|
|
return SetIv(iv);
|
2016-03-17 17:03:19 +00:00
|
|
|
}
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
size_t AesCbcDecryptor::RequiredOutputSize(size_t plaintext_size) {
|
2024-02-08 18:16:52 +00:00
|
|
|
return plaintext_size;
|
2023-12-01 17:32:19 +00:00
|
|
|
}
|
|
|
|
|
2016-04-06 00:19:16 +00:00
|
|
|
bool AesCbcDecryptor::CryptInternal(const uint8_t* ciphertext,
|
|
|
|
size_t ciphertext_size,
|
|
|
|
uint8_t* plaintext,
|
|
|
|
size_t* plaintext_size) {
|
2016-03-25 18:02:43 +00:00
|
|
|
DCHECK(plaintext_size);
|
|
|
|
// Plaintext size is the same as ciphertext size except for pkcs5 padding.
|
2016-04-06 00:19:16 +00:00
|
|
|
// Will update later if using pkcs5 padding. For pkcs5 padding, we still
|
|
|
|
// need at least |ciphertext_size| bytes for intermediate operation.
|
2024-02-08 18:16:52 +00:00
|
|
|
if (*plaintext_size < ciphertext_size) {
|
|
|
|
LOG(ERROR) << "Expecting output size of at least " << ciphertext_size
|
|
|
|
<< " bytes.";
|
2016-04-06 00:19:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
2024-02-08 18:16:52 +00:00
|
|
|
*plaintext_size = ciphertext_size;
|
2016-04-06 00:19:16 +00:00
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
// If the ciphertext size is 0, this can be a no-op decrypt, so long as the
|
|
|
|
// padding mode isn't PKCS5.
|
2016-03-25 18:02:43 +00:00
|
|
|
if (ciphertext_size == 0) {
|
|
|
|
if (padding_scheme_ == kPkcs5Padding) {
|
|
|
|
LOG(ERROR) << "Expected ciphertext to be at least " << AES_BLOCK_SIZE
|
2016-04-06 00:19:16 +00:00
|
|
|
<< " bytes with Pkcs5 padding.";
|
2016-03-25 18:02:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2016-03-17 17:03:19 +00:00
|
|
|
}
|
2016-03-25 18:02:43 +00:00
|
|
|
DCHECK(plaintext);
|
|
|
|
|
|
|
|
const size_t residual_block_size = ciphertext_size % AES_BLOCK_SIZE;
|
2016-04-13 23:43:55 +00:00
|
|
|
const size_t cbc_size = ciphertext_size - residual_block_size;
|
2016-03-25 18:02:43 +00:00
|
|
|
if (residual_block_size == 0) {
|
2024-02-08 18:16:52 +00:00
|
|
|
CbcDecryptBlocks(ciphertext, ciphertext_size, plaintext,
|
|
|
|
internal_iv_.data());
|
2016-03-25 18:02:43 +00:00
|
|
|
if (padding_scheme_ != kPkcs5Padding)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Strip off PKCS5 padding bytes.
|
|
|
|
const uint8_t num_padding_bytes = plaintext[ciphertext_size - 1];
|
|
|
|
if (num_padding_bytes > AES_BLOCK_SIZE) {
|
|
|
|
LOG(ERROR) << "Padding length is too large : "
|
|
|
|
<< static_cast<int>(num_padding_bytes);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*plaintext_size -= num_padding_bytes;
|
|
|
|
return true;
|
2016-04-13 23:43:55 +00:00
|
|
|
} else if (padding_scheme_ == kNoPadding) {
|
2024-02-08 18:16:52 +00:00
|
|
|
if (cbc_size > 0) {
|
|
|
|
CbcDecryptBlocks(ciphertext, cbc_size, plaintext, internal_iv_.data());
|
|
|
|
}
|
2016-04-13 23:43:55 +00:00
|
|
|
// The residual block is not encrypted.
|
2024-02-08 18:16:52 +00:00
|
|
|
memcpy(plaintext + cbc_size, ciphertext + cbc_size, residual_block_size);
|
2016-04-13 23:43:55 +00:00
|
|
|
return true;
|
2016-03-25 18:02:43 +00:00
|
|
|
} else if (padding_scheme_ != kCtsPadding) {
|
|
|
|
LOG(ERROR) << "Expecting cipher text size to be multiple of "
|
|
|
|
<< AES_BLOCK_SIZE << ", got " << ciphertext_size;
|
2016-03-17 17:03:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-25 18:02:43 +00:00
|
|
|
DCHECK_EQ(padding_scheme_, kCtsPadding);
|
2016-03-17 17:03:19 +00:00
|
|
|
if (ciphertext_size < AES_BLOCK_SIZE) {
|
|
|
|
// Don't have a full block, leave unencrypted.
|
|
|
|
memcpy(plaintext, ciphertext, ciphertext_size);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// AES-CBC decrypt everything up to the next-to-last full block.
|
|
|
|
if (cbc_size > AES_BLOCK_SIZE) {
|
2024-02-08 18:16:52 +00:00
|
|
|
CbcDecryptBlocks(ciphertext, cbc_size - AES_BLOCK_SIZE, plaintext,
|
|
|
|
internal_iv_.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint8_t* next_to_last_ciphertext_block =
|
|
|
|
ciphertext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE;
|
|
|
|
uint8_t* next_to_last_plaintext_block =
|
|
|
|
plaintext + ciphertext_size - residual_block_size - AES_BLOCK_SIZE;
|
|
|
|
|
|
|
|
// Determine what the last IV should be so that we can "skip ahead" in the
|
|
|
|
// CBC decryption.
|
|
|
|
std::vector<uint8_t> last_iv(
|
|
|
|
ciphertext + ciphertext_size - residual_block_size,
|
|
|
|
ciphertext + 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.
|
|
|
|
CbcDecryptBlocks(next_to_last_ciphertext_block, AES_BLOCK_SIZE,
|
|
|
|
next_to_last_plaintext_block, last_iv.data());
|
|
|
|
|
|
|
|
// Swap back the residual block bits and the next-to-last block.
|
|
|
|
if (plaintext == ciphertext) {
|
|
|
|
std::swap_ranges(next_to_last_plaintext_block,
|
|
|
|
next_to_last_plaintext_block + residual_block_size,
|
|
|
|
next_to_last_plaintext_block + AES_BLOCK_SIZE);
|
|
|
|
} else {
|
|
|
|
memcpy(next_to_last_plaintext_block + AES_BLOCK_SIZE,
|
|
|
|
next_to_last_plaintext_block, residual_block_size);
|
|
|
|
memcpy(next_to_last_plaintext_block,
|
|
|
|
next_to_last_ciphertext_block + AES_BLOCK_SIZE, residual_block_size);
|
2016-03-17 17:03:19 +00:00
|
|
|
}
|
|
|
|
|
2024-02-08 18:16:52 +00:00
|
|
|
// Decrypt the next-to-last full block.
|
|
|
|
CbcDecryptBlocks(next_to_last_plaintext_block, AES_BLOCK_SIZE,
|
|
|
|
next_to_last_plaintext_block, internal_iv_.data());
|
2016-03-17 17:03:19 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-13 17:52:41 +00:00
|
|
|
void AesCbcDecryptor::SetIvInternal() {
|
|
|
|
internal_iv_ = iv();
|
|
|
|
internal_iv_.resize(AES_BLOCK_SIZE, 0);
|
|
|
|
}
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
void AesCbcDecryptor::CbcDecryptBlocks(const uint8_t* ciphertext,
|
|
|
|
size_t ciphertext_size,
|
2024-02-08 18:16:52 +00:00
|
|
|
uint8_t* plaintext,
|
|
|
|
uint8_t* iv) {
|
2023-12-01 17:32:19 +00:00
|
|
|
CHECK_EQ(ciphertext_size % AES_BLOCK_SIZE, 0u);
|
|
|
|
CHECK_GT(ciphertext_size, 0u);
|
|
|
|
|
|
|
|
// Copy the final block of ciphertext before decryption, since we could be
|
|
|
|
// decrypting in-place.
|
|
|
|
const uint8_t* last_block = ciphertext + ciphertext_size - AES_BLOCK_SIZE;
|
|
|
|
std::vector<uint8_t> next_iv(last_block, last_block + AES_BLOCK_SIZE);
|
|
|
|
|
|
|
|
size_t output_size = 0;
|
2024-02-08 18:16:52 +00:00
|
|
|
CHECK_EQ(mbedtls_cipher_crypt(&cipher_ctx_, iv, AES_BLOCK_SIZE, ciphertext,
|
|
|
|
ciphertext_size, plaintext, &output_size),
|
2023-12-01 17:32:19 +00:00
|
|
|
0);
|
|
|
|
DCHECK_EQ(output_size % AES_BLOCK_SIZE, 0u);
|
|
|
|
|
2024-02-08 18:16:52 +00:00
|
|
|
memcpy(iv, next_iv.data(), next_iv.size());
|
2023-12-01 17:32:19 +00:00
|
|
|
}
|
|
|
|
|
2016-03-17 17:03:19 +00:00
|
|
|
} // namespace media
|
2016-05-20 21:19:33 +00:00
|
|
|
} // namespace shaka
|