• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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