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