1 /*
2 * Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the License); you may
5 * not use this file except in compliance with the License.
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 */
9
10
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <gmssl/hash_drbg.h>
16 #include <gmssl/error.h>
17 #include <gmssl/endian.h>
18
19
hash_df(const DIGEST * digest,const uint8_t * in,size_t inlen,size_t outlen,uint8_t * out)20 static int hash_df(const DIGEST *digest, const uint8_t *in, size_t inlen,
21 size_t outlen, uint8_t *out)
22 {
23 int ret = 0;
24 DIGEST_CTX ctx;
25 uint8_t counter;
26 uint8_t outbits[4];
27 unsigned char dgst[64];
28 size_t len;
29
30 counter = 0x01;
31 PUTU32(outbits, (uint32_t)outlen << 3);
32
33 while (outlen > 0) {
34 if (digest_init(&ctx, digest) != 1
35 || digest_update(&ctx, &counter, sizeof(counter)) != 1
36 || digest_update(&ctx, outbits, sizeof(outbits)) != 1
37 || digest_update(&ctx, in, inlen) != 1
38 || digest_finish(&ctx, dgst, &len) != 1) {
39 goto end;
40 }
41
42 if (outlen < len) {
43 len = outlen;
44 }
45 memcpy(out, dgst, len);
46 out += len;
47 outlen -= len;
48
49 counter++;
50 }
51
52 ret = 1;
53 end:
54 memset(&ctx, 0, sizeof(ctx));
55 memset(dgst, 0, sizeof(dgst));
56 return ret;
57 }
58
hash_drbg_init(HASH_DRBG * drbg,const DIGEST * digest,const uint8_t * entropy,size_t entropy_len,const uint8_t * nonce,size_t nonce_len,const uint8_t * personalstr,size_t personalstr_len)59 int hash_drbg_init(HASH_DRBG *drbg, const DIGEST *digest,
60 const uint8_t *entropy, size_t entropy_len,
61 const uint8_t *nonce, size_t nonce_len,
62 const uint8_t *personalstr, size_t personalstr_len)
63 {
64 int ret = 0;
65 unsigned char *seed_material = NULL;
66 size_t seed_material_len;
67 uint8_t buf[1 + HASH_DRBG_MAX_SEED_SIZE];
68 uint8_t *p;
69
70 memset(drbg, 0, sizeof(HASH_DRBG));
71
72 /* set digest */
73 drbg->digest = digest;
74
75 /* set seedlen */
76 if (digest->digest_size <= 32) {
77 drbg->seedlen = HASH_DRBG_SM3_SEED_SIZE;
78 } else {
79 drbg->seedlen = HASH_DRBG_SHA512_SEED_SIZE;
80 }
81
82 /* seed_material = entropy_input || nonce || personalization_string */
83 seed_material_len = entropy_len + nonce_len + personalstr_len;
84 if (!(seed_material = malloc(seed_material_len))) {
85 return 0;
86 }
87 p = seed_material;
88 memcpy(p, entropy, entropy_len);
89 p += entropy_len;
90 memcpy(p, nonce, nonce_len);
91 p += nonce_len;
92 memcpy(p, personalstr, personalstr_len);
93
94 /* V = Hash_df (seed_material, seedlen) */
95 if (!hash_df(drbg->digest, seed_material, seed_material_len, drbg->seedlen,
96 drbg->V)) {
97 goto end;
98 }
99
100 /* C = Hash_df ((0x00 || V), seedlen) */
101 buf[0] = 0x00;
102 memcpy(buf + 1, drbg->V, drbg->seedlen);
103 if (!hash_df(drbg->digest, buf, 1 + drbg->seedlen, drbg->seedlen,
104 drbg->C)) {
105 goto end;
106 }
107
108 /* reseed_counter = 1 */
109 drbg->reseed_counter = 1;
110
111 ret = 1;
112 end:
113 if (seed_material) {
114 memset(seed_material, 0, seed_material_len);
115 free(seed_material);
116 }
117 memset(buf, 0, sizeof(buf));
118 return ret;
119 }
120
hash_drbg_reseed(HASH_DRBG * drbg,const uint8_t * entropy,size_t entropy_len,const uint8_t * additional,size_t additional_len)121 int hash_drbg_reseed(HASH_DRBG *drbg,
122 const uint8_t *entropy, size_t entropy_len,
123 const uint8_t *additional, size_t additional_len)
124 {
125 int ret = 0;
126 uint8_t *seed_material = NULL;
127 size_t seed_material_len;
128 uint8_t *p;
129 uint8_t buf[1 + HASH_DRBG_MAX_SEED_SIZE];
130
131 /* seed_material = 0x01 || V || entropy_input || additional_input */
132 seed_material_len = 1 + drbg->seedlen + entropy_len + additional_len;
133 if (!(seed_material = malloc(seed_material_len))) {
134 return 0;
135 }
136 seed_material[0] = 0x01;
137 p = seed_material + 1;
138 memcpy(p, drbg->V, drbg->seedlen);
139 p += drbg->seedlen;
140 memcpy(p, entropy, entropy_len);
141 p += entropy_len;
142 memcpy(p, additional, additional_len);
143
144 /* V = Hash_df(seed_material, seedlen) */
145 if (!hash_df(drbg->digest, seed_material, seed_material_len, drbg->seedlen,
146 drbg->V)) {
147 goto end;
148 }
149
150 /* C = Hash_df((0x00 || V), seedlen) */
151 buf[0] = 0x00;
152 memcpy(buf + 1, drbg->V, drbg->seedlen);
153 if (!hash_df(drbg->digest, buf, 1 + drbg->seedlen, drbg->seedlen,
154 drbg->C)) {
155 goto end;
156 }
157
158 /* reseed_counter = 1 */
159 drbg->reseed_counter = 1;
160
161 ret = 1;
162 end:
163 if (seed_material) {
164 memset(seed_material, 0, seed_material_len);
165 free(seed_material);
166 }
167 memset(buf, 0, sizeof(buf));
168 return ret;
169 }
170
171 /* seedlen is always >= dgstlen
172 * R0 ... Ru-v .. .. .. Ru-1
173 * + A0 A1 A2 .. Av-1
174 */
drbg_add(uint8_t * R,const uint8_t * A,size_t seedlen)175 static void drbg_add(uint8_t *R, const uint8_t *A, size_t seedlen)
176 {
177 int temp = 0;
178 int i;
179 for (i = seedlen - 1; i >= 0; i--) {
180 temp += R[i] + A[i];
181 R[i] = temp & 0xff;
182 temp >>= 8;
183 }
184 }
185
drbg_add1(uint8_t * R,size_t seedlen)186 static void drbg_add1(uint8_t *R, size_t seedlen)
187 {
188 int temp = 1;
189 int i;
190 for (i = seedlen - 1; i >= 0; i--) {
191 temp += R[i];
192 R[i] = temp & 0xff;
193 temp >>= 8;
194 }
195 }
196
drbg_hashgen(HASH_DRBG * drbg,size_t outlen,uint8_t * out)197 static int drbg_hashgen(HASH_DRBG *drbg, size_t outlen, uint8_t *out)
198 {
199 int ret = 0;
200 DIGEST_CTX ctx;
201 uint8_t data[HASH_DRBG_MAX_SEED_SIZE];
202 uint8_t dgst[DIGEST_MAX_SIZE];
203 size_t len;
204
205 /* data = V */
206 memcpy(data, drbg->V, drbg->seedlen);
207
208 while (outlen > 0) {
209
210 /* output Hash(data) */
211 if (digest_init(&ctx, drbg->digest) != 1
212 || digest_update(&ctx, data, drbg->seedlen) != 1
213 || digest_finish(&ctx, dgst, &len) != 1) {
214 goto end;
215 }
216
217 if (outlen < len) {
218 len = outlen;
219 }
220 memcpy(out, dgst, len);
221 out += len;
222 outlen -= len;
223
224 /* data = (data + 1) mod 2^seedlen */
225 drbg_add1(data, drbg->seedlen);
226 }
227
228 ret = 1;
229 end:
230 memset(&ctx, 0, sizeof(ctx));
231 memset(data, 0, sizeof(data));
232 return ret;
233 }
234
hash_drbg_generate(HASH_DRBG * drbg,const uint8_t * additional,size_t additional_len,size_t outlen,uint8_t * out)235 int hash_drbg_generate(HASH_DRBG *drbg,
236 const uint8_t *additional, size_t additional_len,
237 size_t outlen, uint8_t *out)
238 {
239 int ret = 0;
240 DIGEST_CTX ctx;
241 uint8_t prefix;
242 uint8_t T[HASH_DRBG_MAX_SEED_SIZE];
243 uint8_t dgst[DIGEST_MAX_SIZE];
244 size_t dgstlen;
245
246 // FIXME: check outlen max value
247
248 if (drbg->reseed_counter > HASH_DRBG_RESEED_INTERVAL) {
249 return 0;
250 }
251
252 if (additional) {
253 /* w = Hash (0x02 || V || additional_input) */
254 prefix = 0x02;
255 if (digest_init(&ctx, drbg->digest) != 1
256 || digest_update(&ctx, &prefix, 1) != 1
257 || digest_update(&ctx, drbg->V, drbg->seedlen) != 1
258 || digest_update(&ctx, additional, additional_len) != 1
259 || digest_finish(&ctx, dgst, &dgstlen) != 1) {
260 goto end;
261 }
262
263 /* V = (V + w) mod 2^seedlen */
264 memset(T, 0, drbg->seedlen - dgstlen);
265 memcpy(T + drbg->seedlen - dgstlen, dgst, dgstlen);
266 drbg_add(drbg->V, T, drbg->seedlen);
267 }
268
269 /* (returned_bits) = Hashgen (requested_number_of_bits, V). */
270 drbg_hashgen(drbg, outlen, out);
271
272 /* H = Hash (0x03 || V). */
273 prefix = 0x03;
274 if (digest_init(&ctx, drbg->digest) != 1
275 || digest_update(&ctx, &prefix, 1) != 1
276 || digest_update(&ctx, drbg->V, drbg->seedlen) != 1
277 || digest_finish(&ctx, dgst, &dgstlen) != 1) {
278 goto end;
279 }
280
281 /* V = (V + H + C + reseed_counter) mod 2^seedlen */
282 memset(T, 0, drbg->seedlen - dgstlen);
283 memcpy(T + drbg->seedlen - dgstlen, dgst, dgstlen);
284 drbg_add(drbg->V, T, drbg->seedlen);
285
286 drbg_add(drbg->V, drbg->C, drbg->seedlen);
287
288 memset(T, 0, drbg->seedlen - sizeof(uint64_t));
289 PUTU64(T + drbg->seedlen - sizeof(uint64_t), drbg->reseed_counter);
290 drbg_add(drbg->V, T, drbg->seedlen);
291
292 /* reseed_counter = reseed_counter + 1 */
293 drbg->reseed_counter++;
294
295 ret = 1;
296 end:
297 memset(&ctx, 0, sizeof(ctx));
298 memset(T, 0, sizeof(T));
299 memset(dgst, 0, sizeof(dgst));
300 return ret;
301 }
302