]>
Commit | Line | Data |
---|---|---|
0c1f3509 MG |
1 | #include <assert.h> |
2 | #include <stdint.h> | |
3 | #include <string.h> | |
4 | ||
5 | #include "entropy.h" | |
6 | #include "insecure_memzero.h" | |
7 | ||
8 | #include "sha256.h" | |
9 | ||
10 | #include "crypto_entropy.h" | |
11 | ||
12 | /** | |
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. | |
17 | */ | |
18 | ||
19 | /* Internal HMAC_DRBG state. */ | |
20 | static struct { | |
21 | uint8_t Key[32]; | |
22 | uint8_t V[32]; | |
23 | uint32_t reseed_counter; | |
24 | } drbg; | |
25 | ||
26 | /* Set to non-zero once the PRNG has been instantiated. */ | |
27 | static int instantiated = 0; | |
28 | ||
29 | /* Could be as high as 2^48 if we wanted... */ | |
30 | #define RESEED_INTERVAL 256 | |
31 | ||
32 | /* Limited to 2^16 by specification. */ | |
33 | #define GENERATE_MAXLEN 65536 | |
34 | ||
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); | |
39 | ||
40 | /** | |
41 | * instantiate(void): | |
42 | * Initialize the DRBG state. (Section 10.1.2.3) | |
43 | */ | |
44 | static int | |
45 | instantiate(void) | |
46 | { | |
47 | uint8_t seed_material[48]; | |
48 | ||
49 | /* Obtain random seed_material = (entropy_input || nonce). */ | |
50 | if (entropy_read(seed_material, 48)) | |
51 | return (-1); | |
52 | ||
53 | /* Initialize Key, V, and reseed_counter. */ | |
54 | memset(drbg.Key, 0x00, 32); | |
55 | memset(drbg.V, 0x01, 32); | |
56 | drbg.reseed_counter = 1; | |
57 | ||
58 | /* Mix the random seed into the state. */ | |
59 | update(seed_material, 48); | |
60 | ||
61 | /* Clean the stack. */ | |
62 | insecure_memzero(seed_material, 48); | |
63 | ||
64 | /* Success! */ | |
65 | return (0); | |
66 | } | |
67 | ||
68 | /** | |
69 | * update(data, datalen): | |
70 | * Update the DRBG state using the provided data. (Section 10.1.2.2) | |
71 | */ | |
72 | static void | |
73 | update(uint8_t * data, size_t datalen) | |
74 | { | |
75 | HMAC_SHA256_CTX ctx; | |
76 | uint8_t K[32]; | |
77 | uint8_t Vx[33]; | |
78 | ||
79 | /* Load (Key, V) into (K, Vx). */ | |
80 | memcpy(K, drbg.Key, 32); | |
81 | memcpy(Vx, drbg.V, 32); | |
82 | ||
83 | /* K <- HMAC(K, V || 0x00 || data). */ | |
84 | Vx[32] = 0x00; | |
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); | |
89 | ||
90 | /* V <- HMAC(K, V). */ | |
91 | HMAC_SHA256_Buf(K, 32, Vx, 32, Vx); | |
92 | ||
93 | /* If the provided data is non-Null, perform another mixing stage. */ | |
94 | if (datalen != 0) { | |
95 | /* K <- HMAC(K, V || 0x01 || data). */ | |
96 | Vx[32] = 0x01; | |
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); | |
101 | ||
102 | /* V <- HMAC(K, V). */ | |
103 | HMAC_SHA256_Buf(K, 32, Vx, 32, Vx); | |
104 | } | |
105 | ||
106 | /* Copy (K, Vx) back to (Key, V). */ | |
107 | memcpy(drbg.Key, K, 32); | |
108 | memcpy(drbg.V, Vx, 32); | |
109 | ||
110 | /* Clean the stack. */ | |
111 | insecure_memzero(K, 32); | |
112 | insecure_memzero(Vx, 33); | |
113 | } | |
114 | ||
115 | /** | |
116 | * reseed(void): | |
117 | * Reseed the DRBG state (mix in new entropy). (Section 10.1.2.4) | |
118 | */ | |
119 | static int | |
120 | reseed(void) | |
121 | { | |
122 | uint8_t seed_material[32]; | |
123 | ||
124 | /* Obtain random seed_material = entropy_input. */ | |
125 | if (entropy_read(seed_material, 32)) | |
126 | return (-1); | |
127 | ||
128 | /* Mix the random seed into the state. */ | |
129 | update(seed_material, 32); | |
130 | ||
131 | /* Reset the reseed_counter. */ | |
132 | drbg.reseed_counter = 1; | |
133 | ||
134 | /* Clean the stack. */ | |
135 | insecure_memzero(seed_material, 32); | |
136 | ||
137 | /* Success! */ | |
138 | return (0); | |
139 | } | |
140 | ||
141 | /** | |
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) | |
147 | */ | |
148 | static void | |
149 | generate(uint8_t * buf, size_t buflen) | |
150 | { | |
151 | size_t bufpos; | |
152 | ||
153 | assert(buflen <= GENERATE_MAXLEN); | |
154 | assert(drbg.reseed_counter <= RESEED_INTERVAL); | |
155 | ||
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); | |
161 | else | |
162 | memcpy(&buf[bufpos], drbg.V, buflen - bufpos); | |
163 | } | |
164 | ||
165 | /* Mix up state. */ | |
166 | update(NULL, 0); | |
167 | ||
168 | /* We're one data-generation step closer to needing a reseed. */ | |
169 | drbg.reseed_counter += 1; | |
170 | } | |
171 | ||
172 | /** | |
173 | * crypto_entropy_read(buf, buflen): | |
174 | * Fill the buffer with unpredictable bits. | |
175 | */ | |
176 | int | |
177 | crypto_entropy_read(uint8_t * buf, size_t buflen) | |
178 | { | |
179 | size_t bytes_to_provide; | |
180 | ||
181 | /* Instantiate if needed. */ | |
182 | if (instantiated == 0) { | |
183 | /* Try to instantiate the PRNG. */ | |
184 | if (instantiate()) | |
185 | return (-1); | |
186 | ||
187 | /* We have instantiated the PRNG. */ | |
188 | instantiated = 1; | |
189 | } | |
190 | ||
191 | /* Loop until we've filled the buffer. */ | |
192 | while (buflen > 0) { | |
193 | /* Do we need to reseed? */ | |
194 | if (drbg.reseed_counter > RESEED_INTERVAL) { | |
195 | if (reseed()) | |
196 | return (-1); | |
197 | } | |
198 | ||
199 | /* How much data are we generating in this step? */ | |
200 | if (buflen > GENERATE_MAXLEN) | |
201 | bytes_to_provide = GENERATE_MAXLEN; | |
202 | else | |
203 | bytes_to_provide = buflen; | |
204 | ||
205 | /* Generate bytes. */ | |
206 | generate(buf, bytes_to_provide); | |
207 | ||
208 | /* We've done part of the buffer. */ | |
209 | buf += bytes_to_provide; | |
210 | buflen -= bytes_to_provide; | |
211 | } | |
212 | ||
213 | /* Success! */ | |
214 | return (0); | |
215 | } |