1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_CRYPTO_DRBG_HMAC
18
19 #include <stdlib.h>
20 #include <securec.h>
21 #include "crypt_errno.h"
22 #include "crypt_local_types.h"
23 #include "crypt_utils.h"
24 #include "bsl_sal.h"
25 #include "crypt_types.h"
26 #include "bsl_err_internal.h"
27 #include "drbg_local.h"
28
29 #define DRBG_HMAC_MAX_MDLEN (64)
30
31 typedef enum {
32 DRBG_HMAC_SHA1SIZE = 20,
33 DRBG_HMAC_SHA224SIZE = 28,
34 DRBG_HMAC_SHA256SIZE = 32,
35 DRBG_HMAC_SHA384SIZE = 48,
36 DRBG_HMAC_SHA512SIZE = 64,
37 } DRBG_HmacSize;
38
39 typedef struct {
40 uint8_t k[DRBG_HMAC_MAX_MDLEN];
41 uint8_t v[DRBG_HMAC_MAX_MDLEN];
42 uint32_t blockLen;
43 const EAL_MacMethod *hmacMeth;
44 CRYPT_MAC_AlgId macId;
45 void *hmacCtx;
46 } DRBG_HmacCtx;
47
48
Hmac(DRBG_HmacCtx * ctx,uint8_t mark,const CRYPT_Data * provData[],int32_t provDataLen)49 static int32_t Hmac(DRBG_HmacCtx *ctx, uint8_t mark, const CRYPT_Data *provData[], int32_t provDataLen)
50 {
51 int32_t ret;
52 uint32_t ctxKLen = sizeof(ctx->k);
53 uint32_t ctxVLen = sizeof(ctx->v);
54 // K = HMAC (K, V || mark || provided_data). mark can be 0x00 or 0x01,
55 // provided_data = in1 || in2 || in3, private_data can be NULL
56 if ((ret = ctx->hmacMeth->init(ctx->hmacCtx, ctx->k, ctx->blockLen, NULL)) != CRYPT_SUCCESS) {
57 BSL_ERR_PUSH_ERROR(ret);
58 goto EXIT;
59 }
60 if ((ret = ctx->hmacMeth->update(ctx->hmacCtx, ctx->v, ctx->blockLen)) != CRYPT_SUCCESS) {
61 BSL_ERR_PUSH_ERROR(ret);
62 goto EXIT;
63 }
64 if ((ret = ctx->hmacMeth->update(ctx->hmacCtx, &mark, 1)) != CRYPT_SUCCESS) {
65 BSL_ERR_PUSH_ERROR(ret);
66 goto EXIT;
67 }
68 for (int32_t i = 0; i < provDataLen; i++) {
69 if ((ret = ctx->hmacMeth->update(ctx->hmacCtx, provData[i]->data, provData[i]->len)) != CRYPT_SUCCESS) {
70 BSL_ERR_PUSH_ERROR(ret);
71 goto EXIT;
72 }
73 }
74 if ((ret = ctx->hmacMeth->final(ctx->hmacCtx, ctx->k, &ctxKLen)) != CRYPT_SUCCESS) {
75 BSL_ERR_PUSH_ERROR(ret);
76 goto EXIT;
77 }
78 // V = HMAC (K, V).
79 if ((ret = ctx->hmacMeth->init(ctx->hmacCtx, ctx->k, ctx->blockLen, NULL)) != CRYPT_SUCCESS) {
80 BSL_ERR_PUSH_ERROR(ret);
81 goto EXIT;
82 }
83 if ((ret = ctx->hmacMeth->update(ctx->hmacCtx, ctx->v, ctx->blockLen)) != CRYPT_SUCCESS) {
84 BSL_ERR_PUSH_ERROR(ret);
85 goto EXIT;
86 }
87 if ((ret = ctx->hmacMeth->final(ctx->hmacCtx, ctx->v, &ctxVLen)) != CRYPT_SUCCESS) {
88 BSL_ERR_PUSH_ERROR(ret);
89 }
90 EXIT:
91 // clear hmacCtx
92 ctx->hmacMeth->deinit(ctx->hmacCtx);
93 return ret;
94 }
95
96 /**
97 * Ref: NIST.SP.800-90Ar1 https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-90ar1.pdf
98 * Section: 10.1.2.2 HMAC_DRBG Update Process
99 */
DRBG_HmacUpdate(DRBG_Ctx * drbg,const CRYPT_Data * provData[],int32_t provDataLen)100 static int32_t DRBG_HmacUpdate(DRBG_Ctx *drbg, const CRYPT_Data *provData[], int32_t provDataLen)
101 {
102 DRBG_HmacCtx *ctx = (DRBG_HmacCtx *)drbg->ctx;
103 int32_t ret;
104 // K = HMAC (K, V || 0x00 || provided_data). V = HMAC (K, V), provided_data have 3 input
105 ret = Hmac(ctx, 0x00, provData, provDataLen);
106 if (ret != CRYPT_SUCCESS) {
107 BSL_ERR_PUSH_ERROR(ret);
108 return ret;
109 }
110 // If (provided_data = Null), then return K and V. It's not an error, it's algorithmic.
111 if (provDataLen == 0) {
112 return ret;
113 }
114 // K = HMAC (K, V || 0x01 || provided_data). V = HMAC (K, V)
115 ret = Hmac(ctx, 0x01, provData, provDataLen);
116 if (ret != CRYPT_SUCCESS) {
117 BSL_ERR_PUSH_ERROR(ret);
118 }
119 return ret;
120 }
121
122 /**
123 * Ref: NIST.SP.800-90Ar1 https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-90ar1.pdf
124 * Section: 10.1.2.3 Instantiation of HMAC_DRBG
125 */
DRBG_HmacInstantiate(DRBG_Ctx * drbg,const CRYPT_Data * entropyInput,const CRYPT_Data * nonce,const CRYPT_Data * perstr)126 int32_t DRBG_HmacInstantiate(DRBG_Ctx *drbg, const CRYPT_Data *entropyInput, const CRYPT_Data *nonce,
127 const CRYPT_Data *perstr)
128 {
129 DRBG_HmacCtx *ctx = (DRBG_HmacCtx *)drbg->ctx;
130 int32_t ret;
131 const CRYPT_Data *provData[3] = {0}; // We only need 3 at most.
132 int32_t index = 0;
133 if (!CRYPT_IsDataNull(entropyInput)) {
134 provData[index++] = entropyInput;
135 }
136 if (!CRYPT_IsDataNull(nonce)) {
137 provData[index++] = nonce;
138 }
139 if (!CRYPT_IsDataNull(perstr)) {
140 provData[index++] = perstr;
141 }
142
143 // Key = 0x00 00...00.
144 (void)memset_s(ctx->k, sizeof(ctx->k), 0, ctx->blockLen);
145
146 // V = 0x01 01...01.
147 (void)memset_s(ctx->v, sizeof(ctx->v), 1, ctx->blockLen);
148
149 // seed_material = entropy_input || nonce || personalization_string.
150 // (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
151 ret = DRBG_HmacUpdate(drbg, provData, index);
152 if (ret != CRYPT_SUCCESS) {
153 BSL_ERR_PUSH_ERROR(ret);
154 }
155
156 return ret;
157 }
158
159 /**
160 * Ref: NIST.SP.800-90Ar1 https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-90ar1.pdf
161 * Section: 10.1.2.4 HMAC_DRBG Reseed Process
162 */
DRBG_HmacReseed(DRBG_Ctx * drbg,const CRYPT_Data * entropyInput,const CRYPT_Data * adin)163 int32_t DRBG_HmacReseed(DRBG_Ctx *drbg, const CRYPT_Data *entropyInput, const CRYPT_Data *adin)
164 {
165 int32_t ret;
166 // seed_material = entropy_input || additional_input.
167 const CRYPT_Data *seedMaterial[2] = {0}; // This stage only needs 2 at most.
168 int32_t index = 0;
169 if (!CRYPT_IsDataNull(entropyInput)) {
170 seedMaterial[index++] = entropyInput;
171 }
172 if (!CRYPT_IsDataNull(adin)) {
173 seedMaterial[index++] = adin;
174 }
175 // (Key, V) = HMAC_DRBG_Update (seed_material, Key, V).
176 ret = DRBG_HmacUpdate(drbg, seedMaterial, index);
177 if (ret != CRYPT_SUCCESS) {
178 BSL_ERR_PUSH_ERROR(ret);
179 }
180
181 return ret;
182 }
183
184 /**
185 * Ref: NIST.SP.800-90Ar1 https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-90ar1.pdf
186 * Section: 10.1.2.5 HMAC_DRBG Generate Process
187 */
DRBG_HmacGenerate(DRBG_Ctx * drbg,uint8_t * out,uint32_t outLen,const CRYPT_Data * adin)188 int32_t DRBG_HmacGenerate(DRBG_Ctx *drbg, uint8_t *out, uint32_t outLen, const CRYPT_Data *adin)
189 {
190 DRBG_HmacCtx *ctx = (DRBG_HmacCtx *)drbg->ctx;
191 const EAL_MacMethod *hmacMeth = ctx->hmacMeth;
192 const uint8_t *temp = ctx->v;
193 uint32_t tmpLen = ctx->blockLen;
194 uint32_t len = outLen;
195 uint8_t *buf = out;
196 int32_t ret;
197 uint32_t ctxVLen;
198 int32_t hasAdin = CRYPT_IsDataNull(adin) ? 0 : 1;
199 // If additional_input ≠ Null, then (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
200 if (hasAdin == 1) {
201 if ((ret = DRBG_HmacUpdate(drbg, &adin, hasAdin)) != CRYPT_SUCCESS) {
202 BSL_ERR_PUSH_ERROR(ret);
203 return ret;
204 }
205 }
206
207 /**
208 While (len (temp) < requested_number_of_bits) do:
209 V = HMAC (Key, V).
210 temp = temp || V.
211 */
212 while (len > 0) {
213 if ((ret = hmacMeth->init(ctx->hmacCtx, ctx->k, ctx->blockLen, NULL)) != CRYPT_SUCCESS ||
214 (ret = hmacMeth->update(ctx->hmacCtx, temp, ctx->blockLen)) != CRYPT_SUCCESS) {
215 BSL_ERR_PUSH_ERROR(ret);
216 goto EXIT;
217 }
218 if (len <= ctx->blockLen) {
219 break;
220 }
221 if ((ret = hmacMeth->final(ctx->hmacCtx, buf, &tmpLen)) != CRYPT_SUCCESS) {
222 BSL_ERR_PUSH_ERROR(ret);
223 goto EXIT;
224 }
225 temp = buf;
226 buf += ctx->blockLen;
227 len -= ctx->blockLen;
228 }
229
230 ctxVLen = sizeof(ctx->v);
231 if ((ret = hmacMeth->final(ctx->hmacCtx, ctx->v, &ctxVLen)) != CRYPT_SUCCESS) {
232 BSL_ERR_PUSH_ERROR(ret);
233 goto EXIT;
234 }
235 // Intercepts the len-length V-value as an output, and because of len <= blockLen,
236 // length of V is always greater than blockLen,Therefore, this problem does not exist.
237 (void)memcpy_s(buf, len, ctx->v, len);
238
239 // (Key, V) = HMAC_DRBG_Update (additional_input, Key, V).
240 if ((ret = DRBG_HmacUpdate(drbg, &adin, hasAdin)) != CRYPT_SUCCESS) {
241 BSL_ERR_PUSH_ERROR(ret);
242 }
243 EXIT:
244 // clear hmacCtx
245 hmacMeth->deinit(ctx->hmacCtx);
246 return ret;
247 }
248
DRBG_HmacUnInstantiate(DRBG_Ctx * drbg)249 void DRBG_HmacUnInstantiate(DRBG_Ctx *drbg)
250 {
251 DRBG_HmacCtx *ctx = (DRBG_HmacCtx*)drbg->ctx;
252 ctx->hmacMeth->deinit(ctx->hmacCtx);
253 BSL_SAL_CleanseData((void *)(ctx->k), sizeof(ctx->k));
254 BSL_SAL_CleanseData((void *)(ctx->v), sizeof(ctx->v));
255 }
256
DRBG_HmacDup(DRBG_Ctx * drbg)257 DRBG_Ctx *DRBG_HmacDup(DRBG_Ctx *drbg)
258 {
259 DRBG_HmacCtx *ctx = NULL;
260
261 if (drbg == NULL) {
262 return NULL;
263 }
264
265 ctx = (DRBG_HmacCtx*)drbg->ctx;
266
267 return DRBG_NewHmacCtx(ctx->hmacMeth, ctx->macId, &(drbg->seedMeth), drbg->seedCtx);
268 }
269
DRBG_HmacFree(DRBG_Ctx * drbg)270 void DRBG_HmacFree(DRBG_Ctx *drbg)
271 {
272 if (drbg == NULL) {
273 return;
274 }
275
276 DRBG_HmacUnInstantiate(drbg);
277 DRBG_HmacCtx *ctx = (DRBG_HmacCtx*)drbg->ctx;
278 ctx->hmacMeth->freeCtx(ctx->hmacCtx);
279 BSL_SAL_FREE(drbg);
280 return;
281 }
282
DRBG_NewHmacCtxBase(uint32_t hmacSize,DRBG_Ctx * drbg)283 static int32_t DRBG_NewHmacCtxBase(uint32_t hmacSize, DRBG_Ctx *drbg)
284 {
285 switch (hmacSize) {
286 case DRBG_HMAC_SHA1SIZE:
287 drbg->strength = 128; // nist 800-90a specified the length must be 128
288 return CRYPT_SUCCESS;
289 case DRBG_HMAC_SHA224SIZE:
290 drbg->strength = 192; // nist 800-90a specified the length must be 192
291 return CRYPT_SUCCESS;
292 case DRBG_HMAC_SHA256SIZE:
293 case DRBG_HMAC_SHA384SIZE:
294 case DRBG_HMAC_SHA512SIZE:
295 drbg->strength = 256; // nist 800-90a specified the length must be 256
296 return CRYPT_SUCCESS;
297 default:
298 BSL_ERR_PUSH_ERROR(CRYPT_DRBG_ALG_NOT_SUPPORT);
299 return CRYPT_DRBG_ALG_NOT_SUPPORT;
300 }
301 }
302
DRBG_NewHmacCtx(const EAL_MacMethod * hmacMeth,CRYPT_MAC_AlgId macId,const CRYPT_RandSeedMethod * seedMeth,void * seedCtx)303 DRBG_Ctx *DRBG_NewHmacCtx(const EAL_MacMethod *hmacMeth, CRYPT_MAC_AlgId macId,
304 const CRYPT_RandSeedMethod *seedMeth, void *seedCtx)
305 {
306 DRBG_Ctx *drbg = NULL;
307 DRBG_HmacCtx *ctx = NULL;
308 static DRBG_Method meth = {
309 DRBG_HmacInstantiate,
310 DRBG_HmacGenerate,
311 DRBG_HmacReseed,
312 DRBG_HmacUnInstantiate,
313 DRBG_HmacDup,
314 DRBG_HmacFree
315 };
316
317 if (hmacMeth == NULL || seedMeth == NULL) {
318 return NULL;
319 }
320
321 drbg = (DRBG_Ctx*)BSL_SAL_Malloc(sizeof(DRBG_Ctx) + sizeof(DRBG_HmacCtx));
322 if (drbg == NULL) {
323 return NULL;
324 }
325
326 ctx = (DRBG_HmacCtx*)(drbg + 1);
327 ctx->hmacMeth = hmacMeth;
328 ctx->macId = macId;
329 void *macCtx = hmacMeth->newCtx(ctx->macId);
330 if (macCtx == NULL) {
331 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
332 BSL_SAL_FREE(drbg);
333 return NULL;
334 }
335 ctx->hmacCtx = macCtx;
336
337 uint32_t tempLen = 0;
338 int32_t ret = hmacMeth->ctrl(ctx->hmacCtx, CRYPT_CTRL_GET_MACLEN, &tempLen, sizeof(uint32_t));
339 if (ret != CRYPT_SUCCESS) {
340 hmacMeth->freeCtx(ctx->hmacCtx);
341 BSL_SAL_FREE(drbg);
342 return NULL;
343 }
344 ctx->blockLen = tempLen;
345
346 if (DRBG_NewHmacCtxBase(ctx->blockLen, drbg) != CRYPT_SUCCESS) {
347 hmacMeth->freeCtx(ctx->hmacCtx);
348 BSL_SAL_FREE(drbg);
349 return NULL;
350 }
351
352 drbg->state = DRBG_STATE_UNINITIALISED;
353 drbg->reseedInterval = DRBG_MAX_RESEED_INTERVAL;
354
355 drbg->meth = &meth;
356 drbg->ctx = ctx;
357 drbg->seedMeth = *seedMeth;
358 drbg->seedCtx = seedCtx;
359
360 // shift rightwards by 3, converting from bit length to byte length
361 drbg->entropyRange.min = drbg->strength >> 3;
362 drbg->entropyRange.max = DRBG_MAX_LEN;
363
364 drbg->nonceRange.min = drbg->entropyRange.min / DRBG_NONCE_FROM_ENTROPY;
365 drbg->nonceRange.max = DRBG_MAX_LEN;
366
367 drbg->maxPersLen = DRBG_MAX_LEN;
368 drbg->maxAdinLen = DRBG_MAX_LEN;
369 drbg->maxRequest = DRBG_MAX_REQUEST;
370
371 return drbg;
372 }
373 #endif
374