/src/boringssl/crypto/fipsmodule/rand/ctrdrbg.c.inc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2017, Google Inc. |
2 | | * |
3 | | * Permission to use, copy, modify, and/or distribute this software for any |
4 | | * purpose with or without fee is hereby granted, provided that the above |
5 | | * copyright notice and this permission notice appear in all copies. |
6 | | * |
7 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
14 | | |
15 | | #include <openssl/ctrdrbg.h> |
16 | | |
17 | | #include <assert.h> |
18 | | |
19 | | #include <openssl/mem.h> |
20 | | |
21 | | #include "internal.h" |
22 | | #include "../cipher/internal.h" |
23 | | #include "../service_indicator/internal.h" |
24 | | |
25 | | |
26 | | // Section references in this file refer to SP 800-90Ar1: |
27 | | // http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf |
28 | | |
29 | | // See table 3. |
30 | | static const uint64_t kMaxReseedCount = UINT64_C(1) << 48; |
31 | | |
32 | | CTR_DRBG_STATE *CTR_DRBG_new(const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], |
33 | | const uint8_t *personalization, |
34 | 0 | size_t personalization_len) { |
35 | 0 | CTR_DRBG_STATE *drbg = OPENSSL_malloc(sizeof(CTR_DRBG_STATE)); |
36 | 0 | if (drbg == NULL || |
37 | 0 | !CTR_DRBG_init(drbg, entropy, personalization, personalization_len)) { |
38 | 0 | CTR_DRBG_free(drbg); |
39 | 0 | return NULL; |
40 | 0 | } |
41 | | |
42 | 0 | return drbg; |
43 | 0 | } |
44 | | |
45 | 0 | void CTR_DRBG_free(CTR_DRBG_STATE *state) { OPENSSL_free(state); } |
46 | | |
47 | | int CTR_DRBG_init(CTR_DRBG_STATE *drbg, |
48 | | const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], |
49 | 2 | const uint8_t *personalization, size_t personalization_len) { |
50 | | // Section 10.2.1.3.1 |
51 | 2 | if (personalization_len > CTR_DRBG_ENTROPY_LEN) { |
52 | 0 | return 0; |
53 | 0 | } |
54 | | |
55 | 2 | uint8_t seed_material[CTR_DRBG_ENTROPY_LEN]; |
56 | 2 | OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN); |
57 | | |
58 | 2 | for (size_t i = 0; i < personalization_len; i++) { |
59 | 0 | seed_material[i] ^= personalization[i]; |
60 | 0 | } |
61 | | |
62 | | // Section 10.2.1.2 |
63 | | |
64 | | // kInitMask is the result of encrypting blocks with big-endian value 1, 2 |
65 | | // and 3 with the all-zero AES-256 key. |
66 | 2 | static const uint8_t kInitMask[CTR_DRBG_ENTROPY_LEN] = { |
67 | 2 | 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1, |
68 | 2 | 0xc4, 0xcb, 0x73, 0x8b, 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, |
69 | 2 | 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18, 0x72, 0x60, 0x03, 0xca, |
70 | 2 | 0x37, 0xa6, 0x2a, 0x74, 0xd1, 0xa2, 0xf5, 0x8e, 0x75, 0x06, 0x35, 0x8e, |
71 | 2 | }; |
72 | | |
73 | 98 | for (size_t i = 0; i < sizeof(kInitMask); i++) { |
74 | 96 | seed_material[i] ^= kInitMask[i]; |
75 | 96 | } |
76 | | |
77 | 2 | drbg->ctr = aes_ctr_set_key(&drbg->ks, NULL, &drbg->block, seed_material, 32); |
78 | 2 | OPENSSL_memcpy(drbg->counter, seed_material + 32, 16); |
79 | 2 | drbg->reseed_counter = 1; |
80 | | |
81 | 2 | return 1; |
82 | 2 | } |
83 | | |
84 | | static_assert(CTR_DRBG_ENTROPY_LEN % AES_BLOCK_SIZE == 0, |
85 | | "not a multiple of AES block size"); |
86 | | |
87 | | // ctr_inc adds |n| to the last four bytes of |drbg->counter|, treated as a |
88 | | // big-endian number. |
89 | 36.8k | static void ctr32_add(CTR_DRBG_STATE *drbg, uint32_t n) { |
90 | 36.8k | uint32_t ctr = CRYPTO_load_u32_be(drbg->counter + 12); |
91 | 36.8k | CRYPTO_store_u32_be(drbg->counter + 12, ctr + n); |
92 | 36.8k | } |
93 | | |
94 | | static int ctr_drbg_update(CTR_DRBG_STATE *drbg, const uint8_t *data, |
95 | 8.57k | size_t data_len) { |
96 | | // Per section 10.2.1.2, |data_len| must be |CTR_DRBG_ENTROPY_LEN|. Here, we |
97 | | // allow shorter inputs and right-pad them with zeros. This is equivalent to |
98 | | // the specified algorithm but saves a copy in |CTR_DRBG_generate|. |
99 | 8.57k | if (data_len > CTR_DRBG_ENTROPY_LEN) { |
100 | 0 | return 0; |
101 | 0 | } |
102 | | |
103 | 8.57k | uint8_t temp[CTR_DRBG_ENTROPY_LEN]; |
104 | 34.3k | for (size_t i = 0; i < CTR_DRBG_ENTROPY_LEN; i += AES_BLOCK_SIZE) { |
105 | 25.7k | ctr32_add(drbg, 1); |
106 | 25.7k | drbg->block(drbg->counter, temp + i, &drbg->ks); |
107 | 25.7k | } |
108 | | |
109 | 283k | for (size_t i = 0; i < data_len; i++) { |
110 | 274k | temp[i] ^= data[i]; |
111 | 274k | } |
112 | | |
113 | 8.57k | drbg->ctr = aes_ctr_set_key(&drbg->ks, NULL, &drbg->block, temp, 32); |
114 | 8.57k | OPENSSL_memcpy(drbg->counter, temp + 32, 16); |
115 | | |
116 | 8.57k | return 1; |
117 | 8.57k | } |
118 | | |
119 | | int CTR_DRBG_reseed(CTR_DRBG_STATE *drbg, |
120 | | const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], |
121 | | const uint8_t *additional_data, |
122 | 0 | size_t additional_data_len) { |
123 | | // Section 10.2.1.4 |
124 | 0 | uint8_t entropy_copy[CTR_DRBG_ENTROPY_LEN]; |
125 | |
|
126 | 0 | if (additional_data_len > 0) { |
127 | 0 | if (additional_data_len > CTR_DRBG_ENTROPY_LEN) { |
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | 0 | OPENSSL_memcpy(entropy_copy, entropy, CTR_DRBG_ENTROPY_LEN); |
132 | 0 | for (size_t i = 0; i < additional_data_len; i++) { |
133 | 0 | entropy_copy[i] ^= additional_data[i]; |
134 | 0 | } |
135 | |
|
136 | 0 | entropy = entropy_copy; |
137 | 0 | } |
138 | | |
139 | 0 | if (!ctr_drbg_update(drbg, entropy, CTR_DRBG_ENTROPY_LEN)) { |
140 | 0 | return 0; |
141 | 0 | } |
142 | | |
143 | 0 | drbg->reseed_counter = 1; |
144 | |
|
145 | 0 | return 1; |
146 | 0 | } |
147 | | |
148 | | int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len, |
149 | | const uint8_t *additional_data, |
150 | 4.28k | size_t additional_data_len) { |
151 | | // See 9.3.1 |
152 | 4.28k | if (out_len > CTR_DRBG_MAX_GENERATE_LENGTH) { |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | | // See 10.2.1.5.1 |
157 | 4.28k | if (drbg->reseed_counter > kMaxReseedCount) { |
158 | 0 | return 0; |
159 | 0 | } |
160 | | |
161 | 4.28k | if (additional_data_len != 0 && |
162 | 4.28k | !ctr_drbg_update(drbg, additional_data, additional_data_len)) { |
163 | 0 | return 0; |
164 | 0 | } |
165 | | |
166 | | // kChunkSize is used to interact better with the cache. Since the AES-CTR |
167 | | // code assumes that it's encrypting rather than just writing keystream, the |
168 | | // buffer has to be zeroed first. Without chunking, large reads would zero |
169 | | // the whole buffer, flushing the L1 cache, and then do another pass (missing |
170 | | // the cache every time) to “encrypt” it. The code can avoid this by |
171 | | // chunking. |
172 | 4.28k | static const size_t kChunkSize = 8 * 1024; |
173 | | |
174 | 8.33k | while (out_len >= AES_BLOCK_SIZE) { |
175 | 4.04k | size_t todo = kChunkSize; |
176 | 4.04k | if (todo > out_len) { |
177 | 4.04k | todo = out_len; |
178 | 4.04k | } |
179 | | |
180 | 4.04k | todo &= ~(AES_BLOCK_SIZE-1); |
181 | 4.04k | const size_t num_blocks = todo / AES_BLOCK_SIZE; |
182 | | |
183 | 4.04k | if (drbg->ctr) { |
184 | 4.04k | OPENSSL_memset(out, 0, todo); |
185 | 4.04k | ctr32_add(drbg, 1); |
186 | 4.04k | drbg->ctr(out, out, num_blocks, &drbg->ks, drbg->counter); |
187 | 4.04k | ctr32_add(drbg, (uint32_t)(num_blocks - 1)); |
188 | 4.04k | } else { |
189 | 0 | for (size_t i = 0; i < todo; i += AES_BLOCK_SIZE) { |
190 | 0 | ctr32_add(drbg, 1); |
191 | 0 | drbg->block(drbg->counter, out + i, &drbg->ks); |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | 4.04k | out += todo; |
196 | 4.04k | out_len -= todo; |
197 | 4.04k | } |
198 | | |
199 | 4.28k | if (out_len > 0) { |
200 | 3.06k | uint8_t block[AES_BLOCK_SIZE]; |
201 | 3.06k | ctr32_add(drbg, 1); |
202 | 3.06k | drbg->block(drbg->counter, block, &drbg->ks); |
203 | | |
204 | 3.06k | OPENSSL_memcpy(out, block, out_len); |
205 | 3.06k | } |
206 | | |
207 | | // Right-padding |additional_data| in step 2.2 is handled implicitly by |
208 | | // |ctr_drbg_update|, to save a copy. |
209 | 4.28k | if (!ctr_drbg_update(drbg, additional_data, additional_data_len)) { |
210 | 0 | return 0; |
211 | 0 | } |
212 | | |
213 | 4.28k | drbg->reseed_counter++; |
214 | 4.28k | FIPS_service_indicator_update_state(); |
215 | 4.28k | return 1; |
216 | 4.28k | } |
217 | | |
218 | 0 | void CTR_DRBG_clear(CTR_DRBG_STATE *drbg) { |
219 | 0 | OPENSSL_cleanse(drbg, sizeof(CTR_DRBG_STATE)); |
220 | 0 | } |