Initial commit
[authen-passphrase-scrypt.git] / scrypt-1.2.1 / libcperciva / crypto / crypto_entropy.c
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 }
This page took 0.027771 seconds and 4 git commands to generate.