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_ENTROPY) && defined(HITLS_CRYPTO_ENTROPY_SYS)
18
19 #include <stdint.h>
20 #include "securec.h"
21 #include "bsl_err_internal.h"
22 #include "bsl_list.h"
23 #include "crypt_errno.h"
24 #include "crypt_entropy.h"
25 #include "es_entropy_pool.h"
26 #include "es_cf.h"
27 #include "es_noise_source.h"
28
29 struct ES_Entropy {
30 bool isWork; // Whether in working state
31 bool enableTest; // Whether to enable the health test
32 uint32_t poolSize; // Entropy pool size
33 ES_EntropyPool *pool; // Entropy pool
34 ES_CfMethod *cfMeth; // compression function handle
35 BslList *nsList;
36 };
37
38 #define ENTROPY_POOL_SIZE_DEFAULT 4096
39 #define ENTROPY_POOL_SIZE_MIN 512
40 #define ENTROPY_POOL_SIZE_MAX 4096
41
ENTROPY_EsNew(void)42 ENTROPY_EntropySource *ENTROPY_EsNew(void)
43 {
44 ENTROPY_EntropySource *es = BSL_SAL_Malloc(sizeof(ENTROPY_EntropySource));
45 if (es == NULL) {
46 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
47 return NULL;
48 }
49 (void)memset_s(es, sizeof(ENTROPY_EntropySource), 0, sizeof(ENTROPY_EntropySource));
50 es->nsList = ES_NsListCreat();
51 if (es->nsList == NULL) {
52 BSL_SAL_Free(es);
53 return NULL;
54 }
55 es->poolSize = ENTROPY_POOL_SIZE_DEFAULT;
56 es->enableTest = false;
57 return es;
58 }
59
ENTROPY_EsFree(ENTROPY_EntropySource * es)60 void ENTROPY_EsFree(ENTROPY_EntropySource *es)
61 {
62 if (es == NULL) {
63 return;
64 }
65 if (es->isWork == true) {
66 ENTROPY_EsDeinit(es);
67 }
68 BSL_SAL_FREE(es->cfMeth);
69 ES_NsListFree(es->nsList);
70 es->nsList = NULL;
71 BSL_SAL_Free(es);
72 return;
73 }
74
ENTROPY_EsInit(ENTROPY_EntropySource * es)75 int32_t ENTROPY_EsInit(ENTROPY_EntropySource *es)
76 {
77 if (es == NULL || es->cfMeth == NULL) {
78 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
79 return CRYPT_NULL_INPUT;
80 }
81 if (es->isWork) {
82 return CRYPT_SUCCESS;
83 }
84 ES_CfMethod *meth = es->cfMeth;
85 if (meth->init != NULL) {
86 meth->ctx = meth->init(&meth->meth);
87 if (meth->ctx == NULL) {
88 ENTROPY_EsDeinit(es);
89 return CRYPT_ENTROPY_ES_CF_ERROR;
90 }
91 }
92 int32_t ret = ES_NsListInit(es->nsList, es->enableTest);
93 if (ret != CRYPT_SUCCESS) {
94 ENTROPY_EsDeinit(es);
95 return ret;
96 }
97 ES_EntropyPool *pool = ES_EntropyPoolInit(es->poolSize);
98 if (pool == NULL) {
99 ENTROPY_EsDeinit(es);
100 return CRYPT_ENTROPY_ES_POOL_ERROR;
101 }
102 es->pool = pool;
103 es->isWork = true;
104 return CRYPT_SUCCESS;
105 }
106
ENTROPY_EsDeinit(ENTROPY_EntropySource * es)107 void ENTROPY_EsDeinit(ENTROPY_EntropySource *es)
108 {
109 if (es == NULL) {
110 return;
111 }
112 es->isWork = false;
113 ES_EntropyPoolDeInit(es->pool);
114 es->pool = NULL;
115 if (es->cfMeth != NULL && es->cfMeth->deinit != NULL) {
116 es->cfMeth->deinit(es->cfMeth->ctx);
117 es->cfMeth->ctx = NULL;
118 }
119 ES_NsListDeinit(es->nsList);
120 return;
121 }
EsPoolSizeSet(ENTROPY_EntropySource * es,void * data,uint32_t len)122 static int32_t EsPoolSizeSet(ENTROPY_EntropySource *es, void *data, uint32_t len)
123 {
124 if (es->isWork) {
125 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_STATE_ERROR);
126 return CRYPT_ENTROPY_ES_STATE_ERROR;
127 }
128 if (len != sizeof(uint32_t) || *(uint32_t *)data < ENTROPY_POOL_SIZE_MIN ||
129 *(uint32_t *)data > ENTROPY_POOL_SIZE_MAX) {
130 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_CTRL_INVALID_PARAM);
131 return CRYPT_ENTROPY_CTRL_INVALID_PARAM;
132 }
133 es->poolSize = *(uint32_t *)data;
134 return CRYPT_SUCCESS;
135 }
136
EsNsAdd(ENTROPY_EntropySource * es,void * data,uint32_t len)137 static int32_t EsNsAdd(ENTROPY_EntropySource *es, void *data, uint32_t len)
138 {
139 if (es->isWork) {
140 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_STATE_ERROR);
141 return CRYPT_ENTROPY_ES_STATE_ERROR;
142 }
143 if (data == NULL || len != sizeof(CRYPT_EAL_NsPara)) {
144 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
145 return CRYPT_NULL_INPUT;
146 }
147 CRYPT_EAL_NsPara *para = (CRYPT_EAL_NsPara *)data;
148 return ES_NsAdd(es->nsList, para->name, para->autoTest, para->minEntropy, ¶->nsMeth,
149 (const CRYPT_EAL_NsTestPara *)&(para->nsPara));
150 }
151
EsEnableTest(ENTROPY_EntropySource * es,void * data,uint32_t len)152 static int32_t EsEnableTest(ENTROPY_EntropySource *es, void *data, uint32_t len)
153 {
154 if (es->isWork) {
155 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_STATE_ERROR);
156 return CRYPT_ENTROPY_ES_STATE_ERROR;
157 }
158 if (data == NULL || len != sizeof(bool)) {
159 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
160 return CRYPT_NULL_INPUT;
161 }
162 es->enableTest = *(bool *)data;
163 return CRYPT_SUCCESS;
164 }
165
EsNsRemove(ENTROPY_EntropySource * es,void * data,uint32_t len)166 static int32_t EsNsRemove(ENTROPY_EntropySource *es, void *data, uint32_t len)
167 {
168 if (es->isWork) {
169 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_STATE_ERROR);
170 return CRYPT_ENTROPY_ES_STATE_ERROR;
171 }
172 if (data == NULL || len == 0) {
173 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
174 return CRYPT_NULL_INPUT;
175 }
176 return ES_NsRemove(es->nsList, (const char *)data);
177 }
178
EsSetCF(ENTROPY_EntropySource * es,ENTROPY_CFPara * data)179 static int32_t EsSetCF(ENTROPY_EntropySource *es, ENTROPY_CFPara *data)
180 {
181 if (es->isWork) {
182 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_STATE_ERROR);
183 return CRYPT_ENTROPY_ES_STATE_ERROR;
184 }
185 if (es->cfMeth != NULL) {
186 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_CF_ERROR);
187 return CRYPT_ENTROPY_ES_CF_ERROR;
188 }
189 es->cfMeth = ES_CFGetMethod(data->algId, data->md);
190 if (es->cfMeth == NULL) {
191 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_CF_NOT_SUPPORT);
192 return CRYPT_ENTROPY_ES_CF_NOT_SUPPORT;
193 }
194 return CRYPT_SUCCESS;
195 }
196
EsGetSize(ENTROPY_EntropySource * es,int32_t cmd,void * data,uint32_t len)197 static int32_t EsGetSize(ENTROPY_EntropySource *es, int32_t cmd, void *data, uint32_t len)
198 {
199 if (data == NULL || len != sizeof(uint32_t)) {
200 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
201 return CRYPT_NULL_INPUT;
202 }
203 if (!es->isWork) {
204 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_STATE_ERROR);
205 return CRYPT_ENTROPY_ES_STATE_ERROR;
206 }
207 switch (cmd) {
208 case CRYPT_ENTROPY_GET_POOL_SIZE:
209 *(uint32_t *)data = es->poolSize;
210 return CRYPT_SUCCESS;
211 case CRYPT_ENTROPY_POOL_GET_CURRSIZE:
212 *(uint32_t *)data = ES_EntropyPoolGetCurSize(es->pool);
213 return CRYPT_SUCCESS;
214 case CRYPT_ENTROPY_GET_CF_SIZE:
215 *(uint32_t *)data = es->cfMeth->getCfOutLen(es->cfMeth->ctx);
216 return CRYPT_SUCCESS;
217 default:
218 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_CTRL_ERROR);
219 return CRYPT_ENTROPY_ES_CTRL_ERROR;
220 }
221 }
EsGetState(ENTROPY_EntropySource * es,void * data,uint32_t len)222 static int32_t EsGetState(ENTROPY_EntropySource *es, void *data, uint32_t len)
223 {
224 if (data == NULL || len != sizeof(bool)) {
225 BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
226 return CRYPT_INVALID_ARG;
227 }
228 *(bool *)data = es->isWork;
229 return CRYPT_SUCCESS;
230 }
231
ENTROPY_EsCtrl(ENTROPY_EntropySource * es,int32_t cmd,void * data,uint32_t len)232 int32_t ENTROPY_EsCtrl(ENTROPY_EntropySource *es, int32_t cmd, void *data, uint32_t len)
233 {
234 if (es == NULL) {
235 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
236 return CRYPT_NULL_INPUT;
237 }
238 switch (cmd) {
239 case CRYPT_ENTROPY_SET_POOL_SIZE:
240 return EsPoolSizeSet(es, data, len);
241 case CRYPT_ENTROPY_ADD_NS:
242 return EsNsAdd(es, data, len);
243 case CRYPT_ENTROPY_REMOVE_NS:
244 return EsNsRemove(es, data, len);
245 case CRYPT_ENTROPY_ENABLE_TEST:
246 return EsEnableTest(es, data, len);
247 case CRYPT_ENTROPY_SET_CF:
248 return EsSetCF(es, data);
249 case CRYPT_ENTROPY_GET_STATE:
250 return EsGetState(es, data, len);
251 default:
252 return EsGetSize(es, cmd, data, len);
253 }
254 }
255
ENTROPY_EsEntropyGet(ENTROPY_EntropySource * es,uint8_t * data,uint32_t len)256 uint32_t ENTROPY_EsEntropyGet(ENTROPY_EntropySource *es, uint8_t *data, uint32_t len)
257 {
258 if (es == NULL || !es->isWork || data == NULL) {
259 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
260 return 0;
261 }
262 if (ES_EntropyPoolGetCurSize(es->pool) <= 0) {
263 int32_t ret = ENTROPY_EsEntropyGather(es);
264 if (ret != CRYPT_SUCCESS) {
265 return 0;
266 }
267 }
268 return ES_EntropyPoolPopBytes(es->pool, data, len);
269 }
270
EsGetEntropy(ENTROPY_EntropySource * es,uint8_t * buf,uint32_t bufLen,uint32_t entropy)271 static uint32_t EsGetEntropy(ENTROPY_EntropySource *es, uint8_t *buf, uint32_t bufLen, uint32_t entropy)
272 {
273 ES_NoiseSource *ns = NULL;
274 uint32_t needLen = 0;
275 uint32_t curEntropy = 0;
276 uint8_t *data = buf;
277 while (curEntropy < entropy) {
278 uint32_t tmpEntropy = curEntropy;
279 for (ns = BSL_LIST_GET_FIRST(es->nsList); ns != NULL && needLen < bufLen; ns = BSL_LIST_GET_NEXT(es->nsList)) {
280 int32_t ret = ES_NsRead(ns, data, 1);
281 if (ret == CRYPT_SUCCESS) {
282 data++;
283 needLen++;
284 curEntropy += ns->minEntropy;
285 }
286 if (curEntropy >= entropy) {
287 return needLen;
288 }
289 }
290 if (curEntropy == tmpEntropy) {
291 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_NS_NOT_AVA);
292 needLen = 0;
293 break;
294 }
295 }
296 return needLen;
297 }
298
GetMinLen(uint32_t entropy,uint32_t minEntropy)299 static uint32_t GetMinLen(uint32_t entropy, uint32_t minEntropy)
300 {
301 return (uint32_t)(((uint64_t)entropy + (uint64_t)minEntropy - 1) / (uint64_t)minEntropy);
302 }
303
ENTROPY_EsEntropyGather(ENTROPY_EntropySource * es)304 int32_t ENTROPY_EsEntropyGather(ENTROPY_EntropySource *es)
305 {
306 if (es == NULL || es->isWork == false || es->cfMeth == NULL) {
307 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
308 return CRYPT_NULL_INPUT;
309 }
310 ES_CfMethod *meth = es->cfMeth;
311 if ((meth->getCfOutLen(meth->ctx) > (uint32_t)ES_EntropyPoolGetMaxSize(es->pool) -
312 ES_EntropyPoolGetCurSize(es->pool))) {
313 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_POOL_INSUFFICIENT);
314 return CRYPT_ENTROPY_ES_POOL_INSUFFICIENT;
315 }
316 uint32_t minEntropy = ES_NsListGetMinEntropy(es->nsList);
317 uint32_t needEntropy = meth->getNeedEntropy(meth->ctx);
318 uint32_t bufLen = GetMinLen(needEntropy, minEntropy);
319 uint8_t *buf = BSL_SAL_Malloc(bufLen);
320 if (buf == NULL) {
321 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
322 return CRYPT_MEM_ALLOC_FAIL;
323 }
324 uint32_t needLen = EsGetEntropy(es, buf, bufLen, needEntropy);
325 if (needLen == 0) {
326 BSL_SAL_Free(buf);
327 BSL_ERR_PUSH_ERROR(CRYPT_ENTROPY_ES_ENTROPY_NOT_ENOUGH);
328 return CRYPT_ENTROPY_ES_ENTROPY_NOT_ENOUGH;
329 }
330 int32_t ret = meth->update(meth->ctx, buf, needLen);
331 BSL_SAL_Free(buf);
332 if (ret != CRYPT_SUCCESS) {
333 BSL_ERR_PUSH_ERROR(ret);
334 return ret;
335 }
336 uint32_t len;
337 uint8_t *data = meth->getEntropyData(meth->ctx, &len);
338 if (data == NULL) {
339 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
340 return CRYPT_MEM_ALLOC_FAIL;
341 }
342 ret = ES_EntropyPoolPushBytes(es->pool, data, len);
343 (void)memset_s(data, len, 0, len);
344 BSL_SAL_Free(data);
345 return ret;
346 }
347 #endif