/src/boringssl/crypto/fipsmodule/rand/ctrdrbg.cc.inc
Line | Count | Source |
1 | | // Copyright 2017 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/ctrdrbg.h> |
16 | | |
17 | | #include <assert.h> |
18 | | |
19 | | #include <openssl/mem.h> |
20 | | #include <algorithm> |
21 | | |
22 | | #include "../../mem_internal.h" |
23 | | #include "../aes/internal.h" |
24 | | #include "../service_indicator/internal.h" |
25 | | #include "internal.h" |
26 | | |
27 | | |
28 | | using namespace bssl; |
29 | | |
30 | | // Section references in this file refer to SP 800-90Ar1: |
31 | | // http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf |
32 | | |
33 | | // Also see table 3. |
34 | | constexpr uint64_t kMaxReseedCount = UINT64_C(1) << 48; |
35 | | |
36 | | // Implements the BCC function as described in Section 10.3.3. |
37 | | static void bcc(uint8_t out[AES_BLOCK_SIZE], const AES_KEY *aes_key, |
38 | 1.43M | const uint8_t *data, size_t data_len) { |
39 | | // 1. chaining_value = 0^outlen. |
40 | 1.43M | uint8_t *chaining_value = out; |
41 | 1.43M | OPENSSL_memset(chaining_value, 0, AES_BLOCK_SIZE); |
42 | | |
43 | | // 2. n = len (data)/outlen. |
44 | 1.43M | BSSL_CHECK(data_len % AES_BLOCK_SIZE == 0); |
45 | 1.43M | const size_t n = data_len / AES_BLOCK_SIZE; |
46 | | |
47 | 7.19M | for (size_t i = 0; i < n; i++) { |
48 | 5.75M | const uint8_t *block = data + (i * AES_BLOCK_SIZE); |
49 | 5.75M | uint8_t input_block[AES_BLOCK_SIZE]; |
50 | | |
51 | | // 4.1: input_block = chaining_value ⊕ block_i. |
52 | 5.75M | CRYPTO_xor16(input_block, chaining_value, block); |
53 | | |
54 | | // 4.2: chaining_value = Block_Encrypt (Key, input_block). |
55 | 5.75M | BCM_aes_encrypt(input_block, chaining_value, aes_key); |
56 | 5.75M | } |
57 | | |
58 | | // 5. output_block = chaining_value. |
59 | 1.43M | } |
60 | | |
61 | | // Implements the derivation function as described in Section 10.3.2. |
62 | | static int block_cipher_df(uint8_t *out, size_t out_len, const uint8_t *input, |
63 | 479k | size_t input_len) { |
64 | | // Constants for AES-256 |
65 | 479k | constexpr size_t kAESKeyLen = 32; |
66 | 479k | constexpr size_t kAESOutLen = AES_BLOCK_SIZE; |
67 | 479k | constexpr size_t kMaxNumBits = 512; |
68 | | |
69 | 479k | if (out_len > kMaxNumBits / 8 || input_len > (1u << 30)) { |
70 | 0 | return 0; |
71 | 0 | } |
72 | | |
73 | | // 4. S = L || N || input_string || 0x80. |
74 | 479k | const size_t s_rawlen = sizeof(uint32_t) + sizeof(uint32_t) + input_len + 1; |
75 | | // S is padded up to a block size. |
76 | 479k | const size_t s_len = (s_rawlen + kAESOutLen - 1) & ~(kAESOutLen - 1); |
77 | 479k | uint8_t iv_plus_s[/* space used below */ kAESOutLen + 4 + 4 + |
78 | 479k | CTR_DRBG_MAX_ENTROPY_LEN + CTR_DRBG_NONCE_LEN + |
79 | 479k | CTR_DRBG_SEED_LEN + 1 + |
80 | 479k | /* padding */ 7]; |
81 | 479k | if (kAESOutLen + s_len > sizeof(iv_plus_s)) { |
82 | 0 | return 0; |
83 | 0 | } |
84 | 479k | OPENSSL_memset(iv_plus_s, 0, sizeof(iv_plus_s)); |
85 | 479k | uint8_t *s_ptr = iv_plus_s + kAESOutLen; |
86 | | // 2. L = len (input_string)/8. |
87 | 479k | CRYPTO_store_u32_be(s_ptr, (uint32_t)input_len); |
88 | 479k | s_ptr += sizeof(uint32_t); |
89 | | // 3. N = number_of_bits_to_return/8. |
90 | 479k | CRYPTO_store_u32_be(s_ptr, (uint32_t)out_len); |
91 | 479k | s_ptr += sizeof(uint32_t); |
92 | 479k | OPENSSL_memcpy(s_ptr, input, input_len); |
93 | 479k | s_ptr += input_len; |
94 | 479k | *s_ptr = 0x80; |
95 | | |
96 | 479k | uint8_t temp[kAESKeyLen + kAESOutLen]; |
97 | 479k | size_t temp_len = 0; |
98 | | |
99 | | // 8. K = leftmost (0x00010203...1D1E1F, keylen). |
100 | 479k | static const uint8_t kInitialKey[kAESKeyLen] = { |
101 | 479k | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, |
102 | 479k | 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, |
103 | 479k | 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; |
104 | 479k | AES_KEY aes_key; |
105 | 479k | bcm_status status = |
106 | 479k | BCM_aes_set_encrypt_key(kInitialKey, 8 * sizeof(kInitialKey), &aes_key); |
107 | 479k | BSSL_CHECK(status != bcm_status::failure); |
108 | | |
109 | | // 7. i = 0. |
110 | 479k | uint32_t i = 0; |
111 | 1.91M | while (temp_len < sizeof(temp)) { |
112 | | // 9.1 IV = i || 0^(outlen - len(i)). |
113 | 1.43M | CRYPTO_store_u32_be(iv_plus_s, i); |
114 | | |
115 | | // 9.2 temp = temp || BCC (K, (IV || S)). |
116 | 1.43M | bcc(temp + temp_len, &aes_key, iv_plus_s, kAESOutLen + s_len); |
117 | 1.43M | temp_len += kAESOutLen; |
118 | | |
119 | | // 9.3 i = i + 1. |
120 | 1.43M | i++; |
121 | 1.43M | } |
122 | | |
123 | | // 10. K = leftmost (temp, keylen). |
124 | 479k | uint8_t *const k = temp; |
125 | | |
126 | | // 11. X = select (temp, keylen+1, keylen+outlen). |
127 | 479k | uint8_t *const x = temp + kAESKeyLen; |
128 | | |
129 | | // 12. temp = the Null string. |
130 | 479k | temp_len = 0; |
131 | | |
132 | | // Create an AES key schedule for the final encryption steps. |
133 | 479k | status = BCM_aes_set_encrypt_key(k, kAESKeyLen * 8, &aes_key); |
134 | 479k | BSSL_CHECK(status != bcm_status::failure); |
135 | | |
136 | | // 13. While len (temp) < number_of_bits_to_return, do: |
137 | 1.91M | while (temp_len < out_len) { |
138 | | // 13.1 X = Block_Encrypt (K, X). |
139 | 1.43M | BCM_aes_encrypt(x, x, &aes_key); |
140 | | |
141 | | // 13.2 temp = temp || X. |
142 | 1.43M | size_t to_copy = std::min(kAESOutLen, out_len - temp_len); |
143 | 1.43M | OPENSSL_memcpy(out + temp_len, x, to_copy); |
144 | 1.43M | temp_len += to_copy; |
145 | 1.43M | } |
146 | | |
147 | 479k | return 1; |
148 | 479k | } |
149 | | |
150 | | CTR_DRBG_STATE *CTR_DRBG_new(const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], |
151 | | const uint8_t *personalization, |
152 | 0 | size_t personalization_len) { |
153 | 0 | CTR_DRBG_STATE *drbg = New<CTR_DRBG_STATE>(); |
154 | 0 | if (drbg == nullptr || |
155 | 0 | !CTR_DRBG_init(drbg, /*df=*/false, entropy, CTR_DRBG_ENTROPY_LEN, |
156 | 0 | /*nonce=*/nullptr, personalization, personalization_len)) { |
157 | 0 | CTR_DRBG_free(drbg); |
158 | 0 | return nullptr; |
159 | 0 | } |
160 | | |
161 | 0 | return drbg; |
162 | 0 | } |
163 | | |
164 | | CTR_DRBG_STATE *CTR_DRBG_new_df(const uint8_t *entropy, size_t entropy_len, |
165 | | const uint8_t nonce[CTR_DRBG_NONCE_LEN], |
166 | | const uint8_t *personalization, |
167 | 0 | size_t personalization_len) { |
168 | 0 | CTR_DRBG_STATE *drbg = New<CTR_DRBG_STATE>(); |
169 | 0 | if (drbg == nullptr || |
170 | 0 | !CTR_DRBG_init(drbg, /*df=*/true, entropy, entropy_len, nonce, |
171 | 0 | personalization, personalization_len)) { |
172 | 0 | CTR_DRBG_free(drbg); |
173 | 0 | return nullptr; |
174 | 0 | } |
175 | | |
176 | 0 | return drbg; |
177 | 0 | } |
178 | | |
179 | 0 | void CTR_DRBG_free(CTR_DRBG_STATE *state) { Delete(state); } |
180 | | |
181 | | int bssl::CTR_DRBG_init(CTR_DRBG_STATE *drbg, int df, const uint8_t *entropy, |
182 | | size_t entropy_len, |
183 | | const uint8_t nonce[CTR_DRBG_NONCE_LEN], |
184 | | const uint8_t *personalization, |
185 | 8 | size_t personalization_len) { |
186 | | // Section 10.2.1.3.1 and 10.2.1.3.2 |
187 | 8 | if (personalization_len > CTR_DRBG_SEED_LEN || |
188 | 8 | (!df && entropy_len != CTR_DRBG_ENTROPY_LEN) || |
189 | 8 | (df && (entropy_len < CTR_DRBG_MIN_ENTROPY_LEN || |
190 | 8 | entropy_len > CTR_DRBG_MAX_ENTROPY_LEN)) || // |
191 | 8 | (df != (nonce != nullptr))) { |
192 | 0 | return 0; |
193 | 0 | } |
194 | | |
195 | 8 | uint8_t seed_material[CTR_DRBG_SEED_LEN]; |
196 | 8 | if (df) { |
197 | 8 | uint8_t pre_seed_material[CTR_DRBG_MAX_ENTROPY_LEN + CTR_DRBG_NONCE_LEN + |
198 | 8 | CTR_DRBG_SEED_LEN]; |
199 | 8 | OPENSSL_memcpy(pre_seed_material, entropy, entropy_len); |
200 | 8 | OPENSSL_memcpy(pre_seed_material + entropy_len, nonce, CTR_DRBG_NONCE_LEN); |
201 | 8 | OPENSSL_memcpy(pre_seed_material + entropy_len + CTR_DRBG_NONCE_LEN, |
202 | 8 | personalization, personalization_len); |
203 | 8 | const size_t pre_seed_material_length = |
204 | 8 | entropy_len + CTR_DRBG_NONCE_LEN + personalization_len; |
205 | | |
206 | 8 | if (!block_cipher_df(seed_material, sizeof(seed_material), |
207 | 8 | pre_seed_material, pre_seed_material_length)) { |
208 | 0 | return 0; |
209 | 0 | } |
210 | 8 | } else { |
211 | 0 | OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN); |
212 | 0 | for (size_t i = 0; i < personalization_len; i++) { |
213 | 0 | seed_material[i] ^= personalization[i]; |
214 | 0 | } |
215 | 0 | } |
216 | | |
217 | | // Section 10.2.1.2 |
218 | | |
219 | | // kInitMask is the result of encrypting blocks with big-endian value 1, 2 |
220 | | // and 3 with the all-zero AES-256 key. |
221 | 8 | static const uint8_t kInitMask[CTR_DRBG_SEED_LEN] = { |
222 | 8 | 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1, |
223 | 8 | 0xc4, 0xcb, 0x73, 0x8b, 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, |
224 | 8 | 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18, 0x72, 0x60, 0x03, 0xca, |
225 | 8 | 0x37, 0xa6, 0x2a, 0x74, 0xd1, 0xa2, 0xf5, 0x8e, 0x75, 0x06, 0x35, 0x8e, |
226 | 8 | }; |
227 | | |
228 | 392 | for (size_t i = 0; i < sizeof(kInitMask); i++) { |
229 | 384 | seed_material[i] ^= kInitMask[i]; |
230 | 384 | } |
231 | | |
232 | 8 | drbg->df = df; |
233 | 8 | drbg->ctr = |
234 | 8 | aes_ctr_set_key(&drbg->ks, nullptr, &drbg->block, seed_material, 32); |
235 | 8 | OPENSSL_memcpy(drbg->counter, seed_material + 32, 16); |
236 | 8 | drbg->reseed_counter = 1; |
237 | | |
238 | 8 | return 1; |
239 | 8 | } |
240 | | |
241 | | static_assert(CTR_DRBG_SEED_LEN % AES_BLOCK_SIZE == 0, |
242 | | "not a multiple of AES block size"); |
243 | | |
244 | | // ctr_inc adds |n| to the last four bytes of |drbg->counter|, treated as a |
245 | | // big-endian number. |
246 | 3.68M | static void ctr32_add(CTR_DRBG_STATE *drbg, uint32_t n) { |
247 | 3.68M | uint32_t ctr = CRYPTO_load_u32_be(drbg->counter + 12); |
248 | 3.68M | CRYPTO_store_u32_be(drbg->counter + 12, ctr + n); |
249 | 3.68M | } |
250 | | |
251 | | static int ctr_drbg_update(CTR_DRBG_STATE *drbg, |
252 | 959k | const uint8_t data[CTR_DRBG_SEED_LEN]) { |
253 | 959k | uint8_t temp[CTR_DRBG_SEED_LEN]; |
254 | 3.83M | for (size_t i = 0; i < CTR_DRBG_SEED_LEN; i += AES_BLOCK_SIZE) { |
255 | 2.87M | ctr32_add(drbg, 1); |
256 | 2.87M | drbg->block(drbg->counter, temp + i, &drbg->ks); |
257 | 2.87M | } |
258 | | |
259 | 46.9M | for (size_t i = 0; i < CTR_DRBG_SEED_LEN; i++) { |
260 | 46.0M | temp[i] ^= data[i]; |
261 | 46.0M | } |
262 | | |
263 | 959k | drbg->ctr = aes_ctr_set_key(&drbg->ks, nullptr, &drbg->block, temp, 32); |
264 | 959k | OPENSSL_memcpy(drbg->counter, temp + 32, 16); |
265 | | |
266 | 959k | return 1; |
267 | 959k | } |
268 | | |
269 | | int CTR_DRBG_reseed(CTR_DRBG_STATE *drbg, |
270 | | const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], |
271 | | const uint8_t *additional_data, |
272 | 0 | size_t additional_data_len) { |
273 | 0 | return CTR_DRBG_reseed_ex(drbg, entropy, CTR_DRBG_ENTROPY_LEN, |
274 | 0 | additional_data, additional_data_len); |
275 | 0 | } |
276 | | |
277 | | int CTR_DRBG_reseed_ex(CTR_DRBG_STATE *drbg, const uint8_t *entropy, |
278 | | size_t entropy_len, const uint8_t *additional_data, |
279 | 114 | size_t additional_data_len) { |
280 | 114 | if (additional_data_len > CTR_DRBG_SEED_LEN || |
281 | 114 | (drbg->df && (entropy_len > CTR_DRBG_MAX_ENTROPY_LEN || |
282 | 114 | entropy_len < CTR_DRBG_MIN_ENTROPY_LEN)) || |
283 | 114 | (!drbg->df && entropy_len != CTR_DRBG_ENTROPY_LEN)) { |
284 | 0 | return 0; |
285 | 0 | } |
286 | | |
287 | 114 | uint8_t seed_material[CTR_DRBG_SEED_LEN]; |
288 | 114 | if (drbg->df) { |
289 | | // Section 10.2.1.4.2 |
290 | 114 | uint8_t pre_seed_material[CTR_DRBG_MAX_ENTROPY_LEN + CTR_DRBG_SEED_LEN]; |
291 | 114 | static_assert(CTR_DRBG_MAX_ENTROPY_LEN <= sizeof(pre_seed_material)); |
292 | 114 | OPENSSL_memcpy(pre_seed_material, entropy, entropy_len); |
293 | 114 | OPENSSL_memcpy(pre_seed_material + entropy_len, additional_data, |
294 | 114 | additional_data_len); |
295 | 114 | const size_t pre_seed_material_len = entropy_len + additional_data_len; |
296 | | |
297 | 114 | if (!block_cipher_df(seed_material, sizeof(seed_material), |
298 | 114 | pre_seed_material, pre_seed_material_len)) { |
299 | 0 | return 0; |
300 | 0 | } |
301 | 114 | } else { |
302 | | // Section 10.2.1.4 |
303 | 0 | static_assert(CTR_DRBG_ENTROPY_LEN == sizeof(seed_material)); |
304 | 0 | OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN); |
305 | 0 | if (additional_data_len > 0) { |
306 | 0 | for (size_t i = 0; i < additional_data_len; i++) { |
307 | 0 | seed_material[i] ^= additional_data[i]; |
308 | 0 | } |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | 114 | if (!ctr_drbg_update(drbg, seed_material)) { |
313 | 0 | return 0; |
314 | 0 | } |
315 | | |
316 | 114 | drbg->reseed_counter = 1; |
317 | | |
318 | 114 | return 1; |
319 | 114 | } |
320 | | |
321 | | int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len, |
322 | | const uint8_t *additional_data, |
323 | 479k | size_t additional_data_len) { |
324 | | // See 9.3.1 |
325 | 479k | if (out_len > CTR_DRBG_MAX_GENERATE_LENGTH) { |
326 | 0 | return 0; |
327 | 0 | } |
328 | | |
329 | | // See 10.2.1.5.1 |
330 | 479k | if (drbg->reseed_counter > kMaxReseedCount) { |
331 | 0 | return 0; |
332 | 0 | } |
333 | | |
334 | 479k | uint8_t processed_additional_data[CTR_DRBG_SEED_LEN]; |
335 | 479k | OPENSSL_memset(processed_additional_data, 0, |
336 | 479k | sizeof(processed_additional_data)); |
337 | 479k | if (additional_data_len != 0) { |
338 | 479k | if (drbg->df) { |
339 | 479k | if (!block_cipher_df(processed_additional_data, |
340 | 479k | sizeof(processed_additional_data), additional_data, |
341 | 479k | additional_data_len)) { |
342 | 0 | return 0; |
343 | 0 | } |
344 | 479k | } else { |
345 | 0 | if (additional_data_len > sizeof(processed_additional_data)) { |
346 | 0 | return 0; |
347 | 0 | } |
348 | 0 | OPENSSL_memcpy(processed_additional_data, additional_data, |
349 | 0 | additional_data_len); |
350 | 0 | } |
351 | 479k | if (!ctr_drbg_update(drbg, processed_additional_data)) { |
352 | 0 | return 0; |
353 | 0 | } |
354 | 479k | } |
355 | | |
356 | | // kChunkSize is used to interact better with the cache. Since the AES-CTR |
357 | | // code assumes that it's encrypting rather than just writing keystream, the |
358 | | // buffer has to be zeroed first. Without chunking, large reads would zero |
359 | | // the whole buffer, flushing the L1 cache, and then do another pass (missing |
360 | | // the cache every time) to “encrypt” it. The code can avoid this by |
361 | | // chunking. |
362 | 479k | constexpr size_t kChunkSize = 8 * 1024; |
363 | | |
364 | 798k | while (out_len >= AES_BLOCK_SIZE) { |
365 | 319k | size_t todo = kChunkSize; |
366 | 319k | if (todo > out_len) { |
367 | 319k | todo = out_len; |
368 | 319k | } |
369 | | |
370 | 319k | todo &= ~(AES_BLOCK_SIZE - 1); |
371 | 319k | const size_t num_blocks = todo / AES_BLOCK_SIZE; |
372 | | |
373 | 319k | OPENSSL_memset(out, 0, todo); |
374 | 319k | ctr32_add(drbg, 1); |
375 | 319k | drbg->ctr(out, out, num_blocks, &drbg->ks, drbg->counter); |
376 | 319k | ctr32_add(drbg, (uint32_t)(num_blocks - 1)); |
377 | | |
378 | 319k | out += todo; |
379 | 319k | out_len -= todo; |
380 | 319k | } |
381 | | |
382 | 479k | if (out_len > 0) { |
383 | 173k | uint8_t block[AES_BLOCK_SIZE]; |
384 | 173k | ctr32_add(drbg, 1); |
385 | 173k | drbg->block(drbg->counter, block, &drbg->ks); |
386 | | |
387 | 173k | OPENSSL_memcpy(out, block, out_len); |
388 | 173k | } |
389 | | |
390 | 479k | if (!ctr_drbg_update(drbg, processed_additional_data)) { |
391 | 0 | return 0; |
392 | 0 | } |
393 | | |
394 | 479k | drbg->reseed_counter++; |
395 | 479k | FIPS_service_indicator_update_state(); |
396 | 479k | return 1; |
397 | 479k | } |
398 | | |
399 | 0 | void CTR_DRBG_clear(CTR_DRBG_STATE *drbg) { |
400 | 0 | OPENSSL_cleanse(drbg, sizeof(CTR_DRBG_STATE)); |
401 | 0 | } |