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 #if defined(HITLS_CRYPTO_EAL) && defined(HITLS_CRYPTO_ENTROPY)
18 #include "securec.h"
19 #include "bsl_err_internal.h"
20 #include "crypt_errno.h"
21 #include "eal_entropy.h"
22
23 #define EAL_MAX_ENTROPY_EVERY_BYTE 8
24 #define EAL_ECF_OUT_LEN 16
25
GetMinLen(void * pool,uint32_t entropy,uint32_t minLen)26 static uint32_t GetMinLen(void *pool, uint32_t entropy, uint32_t minLen)
27 {
28 uint32_t minEntropy = ENTROPY_SeedPoolGetMinEntropy(pool);
29 if (minEntropy == 0) {
30 return 0;
31 }
32 uint32_t len = (uint32_t)(((uint64_t)entropy + (uint64_t)minEntropy - 1) / (uint64_t)minEntropy);
33 /* '<' indicates that the data with a length of len can provide sufficient bit entropy. */
34 if (len < minLen) {
35 len = minLen;
36 }
37 return len;
38 }
39
EAL_EntropyNewCtx(CRYPT_EAL_SeedPoolCtx * seedPool,uint8_t isNpesUsed,uint32_t minLen,uint32_t maxLen,uint32_t entropy)40 EAL_EntropyCtx *EAL_EntropyNewCtx(CRYPT_EAL_SeedPoolCtx *seedPool, uint8_t isNpesUsed, uint32_t minLen,
41 uint32_t maxLen, uint32_t entropy)
42 {
43 if (minLen > maxLen || maxLen == 0) {
44 BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
45 return NULL;
46 }
47 if (!ENTROPY_SeedPoolCheckState(seedPool->pool, isNpesUsed)) {
48 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_STATE_ERROR);
49 return NULL;
50 }
51 if (entropy > maxLen * EAL_MAX_ENTROPY_EVERY_BYTE) {
52 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_RANGE_ERROR);
53 return NULL;
54 }
55 EAL_EntropyCtx *ctx = BSL_SAL_Malloc(sizeof(EAL_EntropyCtx));
56 if (ctx == NULL) {
57 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
58 return NULL;
59 }
60 (void)memset_s(ctx, sizeof(EAL_EntropyCtx), 0, sizeof(EAL_EntropyCtx));
61 ctx->minLen = minLen;
62 ctx->maxLen = maxLen;
63 ctx->isNpesUsed = isNpesUsed;
64 ctx->requestEntropy = entropy;
65 ctx->isNeedFe = (minLen == maxLen) ? true : false;
66 uint32_t needLen;
67 if (ctx->isNeedFe) {
68 ctx->ecfuncId = CRYPT_MAC_CMAC_AES128;
69 ctx->ecfOutLen = EAL_ECF_OUT_LEN;
70 ctx->ecfunc = EAL_EntropyGetECF(CRYPT_MAC_CMAC_AES128);
71 needLen = minLen;
72 } else {
73 needLen = GetMinLen(seedPool->pool, entropy, minLen);
74 }
75 ctx->buf = BSL_SAL_Malloc(needLen);
76 if (ctx->buf == NULL) {
77 BSL_SAL_Free(ctx);
78 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
79 return NULL;
80 }
81 ctx->bufLen = needLen;
82 return ctx;
83 }
84
EAL_EntropyFreeCtx(EAL_EntropyCtx * ctx)85 void EAL_EntropyFreeCtx(EAL_EntropyCtx *ctx)
86 {
87 if (ctx->buf != NULL) {
88 (void)memset_s(ctx->buf, ctx->bufLen, 0, ctx->bufLen);
89 BSL_SAL_FREE(ctx->buf);
90 }
91 BSL_SAL_Free(ctx);
92 }
93
EAL_EntropyObtain(void * seedPool,EAL_EntropyCtx * ctx)94 static int32_t EAL_EntropyObtain(void *seedPool, EAL_EntropyCtx *ctx)
95 {
96 while (ctx->curEntropy < ctx->requestEntropy) {
97 uint32_t needEntropy = ctx->requestEntropy - ctx->curEntropy;
98 uint8_t *buff = ctx->buf + ctx->curLen;
99 uint32_t len = ctx->bufLen - ctx->curLen;
100 uint32_t entropy = ENTROPY_SeedPoolCollect(seedPool, ctx->isNpesUsed, needEntropy, buff, &len);
101 if (entropy == 0) {
102 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NO_ENTROPY_OBTAINED);
103 return CRYPT_SEED_POOL_NO_ENTROPY_OBTAINED;
104 }
105
106 ctx->curEntropy += entropy;
107 ctx->curLen += len;
108 }
109 /*
110 * If the entropy data length is greater than the upper limit, the entropy source quality cannot meet the
111 * requirements and an error is reported.
112 */
113 if (ctx->curLen > ctx->maxLen) {
114 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NOT_MEET_REQUIREMENT);
115 return CRYPT_SEED_POOL_NOT_MEET_REQUIREMENT;
116 }
117 if (ctx->curLen < ctx->minLen) {
118 /*
119 * If the length of the entropy data is less than the lower limit of the required length,
120 * the entropy data that meets the length requirement is read without considering the entropy.
121 */
122 uint32_t len = ctx->minLen - ctx->curLen;
123 uint32_t ent = ENTROPY_SeedPoolCollect(seedPool, true, 0, ctx->buf + ctx->curLen, &len);
124 if (ent == 0 || len != ctx->minLen - ctx->curLen) {
125 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NO_SUFFICIENT_ENTROPY);
126 return CRYPT_SEED_POOL_NO_SUFFICIENT_ENTROPY;
127 }
128 ctx->curLen = ctx->minLen;
129 }
130 return CRYPT_SUCCESS;
131 }
132
EAL_EntropyFesObtain(void * seedPool,EAL_EntropyCtx * ctx)133 static int32_t EAL_EntropyFesObtain(void *seedPool, EAL_EntropyCtx *ctx)
134 {
135 ENTROPY_ECFCtx seedCtx = {ctx->ecfuncId, ctx->ecfOutLen, ctx->ecfunc};
136 int32_t ret = ENTROPY_GetFullEntropyInput(&seedCtx, seedPool, ctx->isNpesUsed, ctx->requestEntropy, ctx->buf,
137 ctx->bufLen);
138 if (ret != CRYPT_SUCCESS) {
139 BSL_ERR_PUSH_ERROR(ret);
140 return ret;
141 }
142 ctx->curEntropy = ctx->requestEntropy;
143 ctx->curLen = ctx->bufLen;
144 return ret;
145 }
146
EAL_EntropyCollection(CRYPT_EAL_SeedPoolCtx * seedPool,EAL_EntropyCtx * ctx)147 int32_t EAL_EntropyCollection(CRYPT_EAL_SeedPoolCtx *seedPool, EAL_EntropyCtx *ctx)
148 {
149 if (!ENTROPY_SeedPoolCheckState(seedPool->pool, true)) {
150 BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_STATE_ERROR);
151 return CRYPT_SEED_POOL_STATE_ERROR;
152 }
153 if (!ctx->isNeedFe || ENTROPY_SeedPoolGetMinEntropy(seedPool->pool) == EAL_MAX_ENTROPY_EVERY_BYTE) {
154 return EAL_EntropyObtain(seedPool->pool, ctx);
155 } else {
156 return EAL_EntropyFesObtain(seedPool->pool, ctx);
157 }
158 }
159
EAL_EntropyDetachBuf(EAL_EntropyCtx * ctx,uint32_t * len)160 uint8_t *EAL_EntropyDetachBuf(EAL_EntropyCtx *ctx, uint32_t *len)
161 {
162 if (ctx->curEntropy < ctx->requestEntropy) {
163 BSL_ERR_PUSH_ERROR(CRYPT_DRBG_FAIL_GET_ENTROPY);
164 return NULL;
165 }
166 uint8_t *data = ctx->buf;
167 *len = ctx->curLen;
168 ctx->buf = NULL;
169 ctx->bufLen = 0;
170 ctx->curLen = 0;
171 ctx->curEntropy = 0;
172 return data;
173 }
174
GetEntropy(void * seedCtx,CRYPT_Data * entropy,uint32_t strength,CRYPT_Range * lenRange)175 static int32_t GetEntropy(void *seedCtx, CRYPT_Data *entropy, uint32_t strength, CRYPT_Range *lenRange)
176 {
177 return CRYPT_EAL_SeedPoolGetEntropy(seedCtx, entropy, strength, lenRange);
178 }
179
CleanEntropy(void * ctx,CRYPT_Data * entropy)180 static void CleanEntropy(void *ctx, CRYPT_Data *entropy)
181 {
182 (void)ctx;
183 BSL_SAL_CleanseData(entropy->data, entropy->len);
184 BSL_SAL_FREE(entropy->data);
185 }
186
GetNonce(void * ctx,CRYPT_Data * nonce,uint32_t strength,CRYPT_Range * lenRange)187 static int32_t GetNonce(void *ctx, CRYPT_Data *nonce, uint32_t strength, CRYPT_Range *lenRange)
188 {
189 return GetEntropy(ctx, nonce, strength, lenRange);
190 }
191
CleanNonce(void * ctx,CRYPT_Data * nonce)192 static void CleanNonce(void *ctx, CRYPT_Data *nonce)
193 {
194 CleanEntropy(ctx, nonce);
195 }
196
EAL_SetDefaultEntropyMeth(CRYPT_RandSeedMethod * meth)197 int32_t EAL_SetDefaultEntropyMeth(CRYPT_RandSeedMethod *meth)
198 {
199 if (meth == NULL) {
200 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
201 return CRYPT_NULL_INPUT;
202 }
203
204 meth->getEntropy = GetEntropy;
205 meth->cleanEntropy = CleanEntropy;
206 meth->cleanNonce = CleanNonce;
207 meth->getNonce = GetNonce;
208 return CRYPT_SUCCESS;
209 }
210
211 #endif
212