Coverage Report

Created: 2026-05-11 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}