ctrdrbg.c
Go to the documentation of this file.
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/rand.h>
16 
17 #include <openssl/type_check.h>
18 #include <openssl/mem.h>
19 
20 #include "internal.h"
21 #include "../cipher/internal.h"
22 
23 
24 // Section references in this file refer to SP 800-90Ar1:
25 // http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf
26 
27 // See table 3.
28 static const uint64_t kMaxReseedCount = UINT64_C(1) << 48;
29 
31  const uint8_t entropy[CTR_DRBG_ENTROPY_LEN],
32  const uint8_t *personalization, size_t personalization_len) {
33  // Section 10.2.1.3.1
34  if (personalization_len > CTR_DRBG_ENTROPY_LEN) {
35  return 0;
36  }
37 
38  uint8_t seed_material[CTR_DRBG_ENTROPY_LEN];
39  OPENSSL_memcpy(seed_material, entropy, CTR_DRBG_ENTROPY_LEN);
40 
41  for (size_t i = 0; i < personalization_len; i++) {
42  seed_material[i] ^= personalization[i];
43  }
44 
45  // Section 10.2.1.2
46 
47  // kInitMask is the result of encrypting blocks with big-endian value 1, 2
48  // and 3 with the all-zero AES-256 key.
49  static const uint8_t kInitMask[CTR_DRBG_ENTROPY_LEN] = {
50  0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1,
51  0xc4, 0xcb, 0x73, 0x8b, 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e,
52  0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18, 0x72, 0x60, 0x03, 0xca,
53  0x37, 0xa6, 0x2a, 0x74, 0xd1, 0xa2, 0xf5, 0x8e, 0x75, 0x06, 0x35, 0x8e,
54  };
55 
56  for (size_t i = 0; i < sizeof(kInitMask); i++) {
57  seed_material[i] ^= kInitMask[i];
58  }
59 
60  drbg->ctr = aes_ctr_set_key(&drbg->ks, NULL, &drbg->block, seed_material, 32);
61  OPENSSL_memcpy(drbg->counter.bytes, seed_material + 32, 16);
62  drbg->reseed_counter = 1;
63 
64  return 1;
65 }
66 
68  "not a multiple of AES block size");
69 
70 // ctr_inc adds |n| to the last four bytes of |drbg->counter|, treated as a
71 // big-endian number.
72 static void ctr32_add(CTR_DRBG_STATE *drbg, uint32_t n) {
73  drbg->counter.words[3] =
75 }
76 
77 static int ctr_drbg_update(CTR_DRBG_STATE *drbg, const uint8_t *data,
78  size_t data_len) {
79  // Per section 10.2.1.2, |data_len| must be |CTR_DRBG_ENTROPY_LEN|. Here, we
80  // allow shorter inputs and right-pad them with zeros. This is equivalent to
81  // the specified algorithm but saves a copy in |CTR_DRBG_generate|.
82  if (data_len > CTR_DRBG_ENTROPY_LEN) {
83  return 0;
84  }
85 
87  for (size_t i = 0; i < CTR_DRBG_ENTROPY_LEN; i += AES_BLOCK_SIZE) {
88  ctr32_add(drbg, 1);
89  drbg->block(drbg->counter.bytes, temp + i, &drbg->ks);
90  }
91 
92  for (size_t i = 0; i < data_len; i++) {
93  temp[i] ^= data[i];
94  }
95 
96  drbg->ctr = aes_ctr_set_key(&drbg->ks, NULL, &drbg->block, temp, 32);
97  OPENSSL_memcpy(drbg->counter.bytes, temp + 32, 16);
98 
99  return 1;
100 }
101 
103  const uint8_t entropy[CTR_DRBG_ENTROPY_LEN],
104  const uint8_t *additional_data,
105  size_t additional_data_len) {
106  // Section 10.2.1.4
107  uint8_t entropy_copy[CTR_DRBG_ENTROPY_LEN];
108 
109  if (additional_data_len > 0) {
110  if (additional_data_len > CTR_DRBG_ENTROPY_LEN) {
111  return 0;
112  }
113 
114  OPENSSL_memcpy(entropy_copy, entropy, CTR_DRBG_ENTROPY_LEN);
115  for (size_t i = 0; i < additional_data_len; i++) {
116  entropy_copy[i] ^= additional_data[i];
117  }
118 
119  entropy = entropy_copy;
120  }
121 
122  if (!ctr_drbg_update(drbg, entropy, CTR_DRBG_ENTROPY_LEN)) {
123  return 0;
124  }
125 
126  drbg->reseed_counter = 1;
127 
128  return 1;
129 }
130 
131 int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len,
132  const uint8_t *additional_data,
133  size_t additional_data_len) {
134  // See 9.3.1
135  if (out_len > CTR_DRBG_MAX_GENERATE_LENGTH) {
136  return 0;
137  }
138 
139  // See 10.2.1.5.1
140  if (drbg->reseed_counter > kMaxReseedCount) {
141  return 0;
142  }
143 
144  if (additional_data_len != 0 &&
145  !ctr_drbg_update(drbg, additional_data, additional_data_len)) {
146  return 0;
147  }
148 
149  // kChunkSize is used to interact better with the cache. Since the AES-CTR
150  // code assumes that it's encrypting rather than just writing keystream, the
151  // buffer has to be zeroed first. Without chunking, large reads would zero
152  // the whole buffer, flushing the L1 cache, and then do another pass (missing
153  // the cache every time) to “encrypt” it. The code can avoid this by
154  // chunking.
155  static const size_t kChunkSize = 8 * 1024;
156 
157  while (out_len >= AES_BLOCK_SIZE) {
158  size_t todo = kChunkSize;
159  if (todo > out_len) {
160  todo = out_len;
161  }
162 
163  todo &= ~(AES_BLOCK_SIZE-1);
164  const size_t num_blocks = todo / AES_BLOCK_SIZE;
165 
166  if (drbg->ctr) {
167  OPENSSL_memset(out, 0, todo);
168  ctr32_add(drbg, 1);
169  drbg->ctr(out, out, num_blocks, &drbg->ks, drbg->counter.bytes);
170  ctr32_add(drbg, num_blocks - 1);
171  } else {
172  for (size_t i = 0; i < todo; i += AES_BLOCK_SIZE) {
173  ctr32_add(drbg, 1);
174  drbg->block(drbg->counter.bytes, out + i, &drbg->ks);
175  }
176  }
177 
178  out += todo;
179  out_len -= todo;
180  }
181 
182  if (out_len > 0) {
184  ctr32_add(drbg, 1);
185  drbg->block(drbg->counter.bytes, block, &drbg->ks);
186 
187  OPENSSL_memcpy(out, block, out_len);
188  }
189 
190  // Right-padding |additional_data| in step 2.2 is handled implicitly by
191  // |ctr_drbg_update|, to save a copy.
192  if (!ctr_drbg_update(drbg, additional_data, additional_data_len)) {
193  return 0;
194  }
195 
196  drbg->reseed_counter++;
197  return 1;
198 }
199 
201  OPENSSL_cleanse(drbg, sizeof(CTR_DRBG_STATE));
202 }
fix_build_deps.temp
temp
Definition: fix_build_deps.py:488
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
CTR_DRBG_STATE::ks
AES_KEY ks
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:100
OPENSSL_cleanse
#define OPENSSL_cleanse
Definition: boringssl_prefix_symbols.h:1864
CTR_DRBG_STATE::reseed_counter
uint64_t reseed_counter
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:107
CTR_DRBG_init
int CTR_DRBG_init(CTR_DRBG_STATE *drbg, const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], const uint8_t *personalization, size_t personalization_len)
Definition: ctrdrbg.c:30
OPENSSL_STATIC_ASSERT
OPENSSL_STATIC_ASSERT(CTR_DRBG_ENTROPY_LEN % AES_BLOCK_SIZE==0, "not a multiple of AES block size")
CTR_DRBG_STATE::counter
union CTR_DRBG_STATE::@355 counter
kChunkSize
static constexpr size_t kChunkSize
Definition: chunked_vector_fuzzer.cc:29
CTR_DRBG_STATE::words
uint32_t words[4]
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:105
CTR_DRBG_MAX_GENERATE_LENGTH
#define CTR_DRBG_MAX_GENERATE_LENGTH
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:112
CTR_DRBG_clear
void CTR_DRBG_clear(CTR_DRBG_STATE *drbg)
Definition: ctrdrbg.c:200
CTR_DRBG_generate
int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len, const uint8_t *additional_data, size_t additional_data_len)
Definition: ctrdrbg.c:131
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
OPENSSL_memset
static void * OPENSSL_memset(void *dst, int c, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:835
CTR_DRBG_STATE::block
block128_f block
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:101
AES_BLOCK_SIZE
#define AES_BLOCK_SIZE
Definition: aes.h:68
block
Block * block
Definition: protobuf/src/google/protobuf/descriptor.cc:1041
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
internal.h
CRYPTO_bswap4
static uint32_t CRYPTO_bswap4(uint32_t x)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:753
aes_ctr_set_key
#define aes_ctr_set_key
Definition: boringssl_prefix_symbols.h:2807
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
OPENSSL_memcpy
static void * OPENSSL_memcpy(void *dst, const void *src, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:819
CTR_DRBG_STATE::bytes
uint8_t bytes[16]
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:104
ctr_drbg_update
static int ctr_drbg_update(CTR_DRBG_STATE *drbg, const uint8_t *data, size_t data_len)
Definition: ctrdrbg.c:77
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
UINT64_C
#define UINT64_C(val)
Definition: stdint-msvc2008.h:238
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
CTR_DRBG_ENTROPY_LEN
#define CTR_DRBG_ENTROPY_LEN
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:111
rand.h
kMaxReseedCount
static const uint64_t kMaxReseedCount
Definition: ctrdrbg.c:28
CTR_DRBG_STATE::ctr
ctr128_f ctr
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:102
ctr32_add
static void ctr32_add(CTR_DRBG_STATE *drbg, uint32_t n)
Definition: ctrdrbg.c:72
mem.h
type_check.h
CTR_DRBG_STATE
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:99
CTR_DRBG_reseed
int CTR_DRBG_reseed(CTR_DRBG_STATE *drbg, const uint8_t entropy[CTR_DRBG_ENTROPY_LEN], const uint8_t *additional_data, size_t additional_data_len)
Definition: ctrdrbg.c:102
mkowners.todo
todo
Definition: mkowners.py:209
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:08