Shaka Packager SDK
Loading...
Searching...
No Matches
aes_cryptor.cc
1// Copyright 2016 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/base/aes_cryptor.h>
8
9#include <string>
10#include <vector>
11
12#include <absl/log/check.h>
13#include <absl/log/log.h>
14#include <mbedtls/entropy.h>
15
16#include <packager/macros/compiler.h>
17#include <packager/macros/crypto.h>
18
19namespace {
20
21// According to ISO/IEC 23001-7:2016 CENC spec, IV should be either
22// 64-bit (8-byte) or 128-bit (16-byte).
23bool IsIvSizeValid(size_t iv_size) {
24 return iv_size == 8 || iv_size == 16;
25}
26
27} // namespace
28
29namespace shaka {
30namespace media {
31
32AesCryptor::AesCryptor(ConstantIvFlag constant_iv_flag)
33 : constant_iv_flag_(constant_iv_flag), num_crypt_bytes_(0) {
34 mbedtls_cipher_init(&cipher_ctx_);
35}
36
37AesCryptor::~AesCryptor() {
38 mbedtls_cipher_free(&cipher_ctx_);
39}
40
41bool AesCryptor::Crypt(const std::vector<uint8_t>& text,
42 std::vector<uint8_t>* crypt_text) {
43 // Save text size to make it work for in-place conversion, since the
44 // next statement will update the text size.
45 const size_t text_size = text.size();
46 crypt_text->resize(text_size + NumPaddingBytes(text_size));
47 size_t crypt_text_size = crypt_text->size();
48 if (!Crypt(text.data(), text_size, crypt_text->data(), &crypt_text_size)) {
49 return false;
50 }
51 DCHECK_LE(crypt_text_size, crypt_text->size());
52 crypt_text->resize(crypt_text_size);
53 return true;
54}
55
56bool AesCryptor::Crypt(const std::string& text, std::string* crypt_text) {
57 // Save text size to make it work for in-place conversion, since the
58 // next statement will update the text size.
59 const size_t text_size = text.size();
60 crypt_text->resize(text_size + NumPaddingBytes(text_size));
61 size_t crypt_text_size = crypt_text->size();
62 if (!Crypt(reinterpret_cast<const uint8_t*>(text.data()), text_size,
63 reinterpret_cast<uint8_t*>(&(*crypt_text)[0]), &crypt_text_size))
64 return false;
65 DCHECK_LE(crypt_text_size, crypt_text->size());
66 crypt_text->resize(crypt_text_size);
67 return true;
68}
69
70bool AesCryptor::SetIv(const std::vector<uint8_t>& iv) {
71 if (!IsIvSizeValid(iv.size())) {
72 LOG(ERROR) << "Invalid IV size: " << iv.size();
73 return false;
74 }
75 iv_ = iv;
76 num_crypt_bytes_ = 0;
77 SetIvInternal();
78 return true;
79}
80
82 if (constant_iv_flag_ == kUseConstantIv)
83 return;
84
85 uint64_t increment = 0;
86 // As recommended in ISO/IEC 23001-7:2016 CENC spec, for 64-bit (8-byte)
87 // IV_Sizes, initialization vectors for subsequent samples can be created by
88 // incrementing the initialization vector of the previous sample.
89 // For 128-bit (16-byte) IV_Sizes, initialization vectors for subsequent
90 // samples should be created by adding the block count of the previous sample
91 // to the initialization vector of the previous sample.
92 // There is no official recommendation of how IV for next sample should be
93 // generated for CBC mode. We use the same generation algorithm as CTR here.
94 if (iv_.size() == 8) {
95 increment = 1;
96 } else {
97 DCHECK_EQ(16u, iv_.size());
98 increment = (num_crypt_bytes_ + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
99 }
100
101 for (int64_t i = iv_.size() - 1; increment > 0 && i >= 0; --i) {
102 increment += iv_[i];
103 iv_[i] = increment & 0xFF;
104 increment >>= 8;
105 }
106 num_crypt_bytes_ = 0;
107 SetIvInternal();
108}
109
110bool AesCryptor::GenerateRandomIv(FourCC protection_scheme,
111 std::vector<uint8_t>* iv) {
112 // ISO/IEC 23001-7:2016 10.1 and 10.3 For 'cenc' and 'cens'
113 // default_Per_Sample_IV_Size and Per_Sample_IV_Size SHOULD be 8-bytes.
114 // There is no official guideline on the iv size for 'cbc1' and 'cbcs',
115 // but 16-byte provides better security.
116 const size_t iv_size =
117 (protection_scheme == FOURCC_cenc || protection_scheme == FOURCC_cens)
118 ? 8
119 : 16;
120 iv->resize(iv_size);
121
122 mbedtls_entropy_context entropy_ctx;
123 mbedtls_entropy_init(&entropy_ctx);
124 int rv = mbedtls_entropy_func(&entropy_ctx, iv->data(), iv_size);
125 mbedtls_entropy_free(&entropy_ctx);
126
127 if (rv != 0) {
128 LOG(ERROR) << "mbedtls_entropy_func failed with: " << rv;
129 return false;
130 }
131 return true;
132}
133
134size_t AesCryptor::NumPaddingBytes(size_t size) const {
135 // No padding by default.
136 UNUSED(size);
137 return 0;
138}
139
140bool AesCryptor::SetupCipher(size_t key_size, CipherMode mode) {
141 mbedtls_cipher_type_t type;
142
143 // AES defines three key sizes: 128, 192 and 256 bits.
144 // NOTE: Because we use ECB mode in the CTR cryptors, this returns ECB
145 // instead of CTR. Counters and block offsets are managed internally.
146 switch (key_size) {
147 case 16:
148 type = mode == kCtrMode ? MBEDTLS_CIPHER_AES_128_ECB
149 : MBEDTLS_CIPHER_AES_128_CBC;
150 break;
151 case 24:
152 type = mode == kCtrMode ? MBEDTLS_CIPHER_AES_192_ECB
153 : MBEDTLS_CIPHER_AES_192_CBC;
154 break;
155 case 32:
156 type = mode == kCtrMode ? MBEDTLS_CIPHER_AES_256_ECB
157 : MBEDTLS_CIPHER_AES_256_CBC;
158 break;
159 default:
160 LOG(ERROR) << "Invalid AES key size: " << key_size;
161 return false;
162 }
163
164 const mbedtls_cipher_info_t* cipher_info =
165 mbedtls_cipher_info_from_type(type);
166 CHECK(cipher_info);
167
168 if (mbedtls_cipher_setup(&cipher_ctx_, cipher_info) != 0) {
169 LOG(ERROR) << "Cipher setup failed";
170 return false;
171 }
172
173 // Padding mode only applies to CBC.
174 if (mode == kCbcMode) {
175 // We handle padding ourselves. Don't let mbedtls mess with it.
176 mbedtls_cipher_padding_t cipher_padding = MBEDTLS_PADDING_NONE;
177
178 if (mbedtls_cipher_set_padding_mode(&cipher_ctx_, cipher_padding) != 0) {
179 LOG(ERROR) << "Failed to set CBC padding mode";
180 return false;
181 }
182 }
183
184 return true;
185}
186
187} // namespace media
188} // namespace shaka
static bool GenerateRandomIv(FourCC protection_scheme, std::vector< uint8_t > *iv)
AesCryptor(ConstantIvFlag constant_iv_flag)
bool SetIv(const std::vector< uint8_t > &iv)
const std::vector< uint8_t > & iv() const
Definition aes_cryptor.h:85
All the methods that are virtual are virtual for mocking.