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