6 #include "insecure_memzero.h"
10 #include "crypto_entropy.h"
13 * This system implements the HMAC_DRBG pseudo-random number generator as
14 * specified in section 10.1.2 of the NIST SP 800-90 standard. In this
15 * implementation, the optional personalization_string and additional_input
16 * specified in the standard are not implemented.
19 /* Internal HMAC_DRBG state. */
23 uint32_t reseed_counter
;
26 /* Set to non-zero once the PRNG has been instantiated. */
27 static int instantiated
= 0;
29 /* Could be as high as 2^48 if we wanted... */
30 #define RESEED_INTERVAL 256
32 /* Limited to 2^16 by specification. */
33 #define GENERATE_MAXLEN 65536
35 static int instantiate(void);
36 static void update(uint8_t *, size_t);
37 static int reseed(void);
38 static void generate(uint8_t *, size_t);
42 * Initialize the DRBG state. (Section 10.1.2.3)
47 uint8_t seed_material
[48];
49 /* Obtain random seed_material = (entropy_input || nonce). */
50 if (entropy_read(seed_material
, 48))
53 /* Initialize Key, V, and reseed_counter. */
54 memset(drbg
.Key
, 0x00, 32);
55 memset(drbg
.V
, 0x01, 32);
56 drbg
.reseed_counter
= 1;
58 /* Mix the random seed into the state. */
59 update(seed_material
, 48);
61 /* Clean the stack. */
62 insecure_memzero(seed_material
, 48);
69 * update(data, datalen):
70 * Update the DRBG state using the provided data. (Section 10.1.2.2)
73 update(uint8_t * data
, size_t datalen
)
79 /* Load (Key, V) into (K, Vx). */
80 memcpy(K
, drbg
.Key
, 32);
81 memcpy(Vx
, drbg
.V
, 32);
83 /* K <- HMAC(K, V || 0x00 || data). */
85 HMAC_SHA256_Init(&ctx
, K
, 32);
86 HMAC_SHA256_Update(&ctx
, Vx
, 33);
87 HMAC_SHA256_Update(&ctx
, data
, datalen
);
88 HMAC_SHA256_Final(K
, &ctx
);
90 /* V <- HMAC(K, V). */
91 HMAC_SHA256_Buf(K
, 32, Vx
, 32, Vx
);
93 /* If the provided data is non-Null, perform another mixing stage. */
95 /* K <- HMAC(K, V || 0x01 || data). */
97 HMAC_SHA256_Init(&ctx
, K
, 32);
98 HMAC_SHA256_Update(&ctx
, Vx
, 33);
99 HMAC_SHA256_Update(&ctx
, data
, datalen
);
100 HMAC_SHA256_Final(K
, &ctx
);
102 /* V <- HMAC(K, V). */
103 HMAC_SHA256_Buf(K
, 32, Vx
, 32, Vx
);
106 /* Copy (K, Vx) back to (Key, V). */
107 memcpy(drbg
.Key
, K
, 32);
108 memcpy(drbg
.V
, Vx
, 32);
110 /* Clean the stack. */
111 insecure_memzero(K
, 32);
112 insecure_memzero(Vx
, 33);
117 * Reseed the DRBG state (mix in new entropy). (Section 10.1.2.4)
122 uint8_t seed_material
[32];
124 /* Obtain random seed_material = entropy_input. */
125 if (entropy_read(seed_material
, 32))
128 /* Mix the random seed into the state. */
129 update(seed_material
, 32);
131 /* Reset the reseed_counter. */
132 drbg
.reseed_counter
= 1;
134 /* Clean the stack. */
135 insecure_memzero(seed_material
, 32);
142 * generate(buf, buflen):
143 * Fill the provided buffer with random bits, assuming that reseed_counter
144 * is less than RESEED_INTERVAL (the caller is responsible for calling
145 * reseed() as needed) and ${buflen} is less than 2^16 (the caller is
146 * responsible for splitting up larger requests). (Section 10.1.2.5)
149 generate(uint8_t * buf
, size_t buflen
)
153 assert(buflen
<= GENERATE_MAXLEN
);
154 assert(drbg
.reseed_counter
<= RESEED_INTERVAL
);
156 /* Iterate until we've filled the buffer. */
157 for (bufpos
= 0; bufpos
< buflen
; bufpos
+= 32) {
158 HMAC_SHA256_Buf(drbg
.Key
, 32, drbg
.V
, 32, drbg
.V
);
159 if (buflen
- bufpos
>= 32)
160 memcpy(&buf
[bufpos
], drbg
.V
, 32);
162 memcpy(&buf
[bufpos
], drbg
.V
, buflen
- bufpos
);
168 /* We're one data-generation step closer to needing a reseed. */
169 drbg
.reseed_counter
+= 1;
173 * crypto_entropy_read(buf, buflen):
174 * Fill the buffer with unpredictable bits.
177 crypto_entropy_read(uint8_t * buf
, size_t buflen
)
179 size_t bytes_to_provide
;
181 /* Instantiate if needed. */
182 if (instantiated
== 0) {
183 /* Try to instantiate the PRNG. */
187 /* We have instantiated the PRNG. */
191 /* Loop until we've filled the buffer. */
193 /* Do we need to reseed? */
194 if (drbg
.reseed_counter
> RESEED_INTERVAL
) {
199 /* How much data are we generating in this step? */
200 if (buflen
> GENERATE_MAXLEN
)
201 bytes_to_provide
= GENERATE_MAXLEN
;
203 bytes_to_provide
= buflen
;
205 /* Generate bytes. */
206 generate(buf
, bytes_to_provide
);
208 /* We've done part of the buffer. */
209 buf
+= bytes_to_provide
;
210 buflen
-= bytes_to_provide
;
This page took 0.027771 seconds and 4 git commands to generate.