• 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_ENTROPY
18 
19 #include <stdint.h>
20 #include "securec.h"
21 #include "bsl_err_internal.h"
22 #include "crypt_errno.h"
23 #include "entropy_seed_pool.h"
24 
25 #define SEEDPOOL_ES_MAX_SIZE 16
26 #define SEEDPOOL_ES_INIT_MINENTROPY 9
27 #define SEEDPOOL_ES_FULL_MINENTROPY 8
28 #define SEEDPOOL_ES_SYS_MINENTROPY 7
29 
ENTROPY_SeedPoolNew(bool isCreateNullPool)30 ENTROPY_SeedPool *ENTROPY_SeedPoolNew(bool isCreateNullPool)
31 {
32     ENTROPY_SeedPool *poolCtx = BSL_SAL_Malloc(sizeof(ENTROPY_SeedPool));
33     if (poolCtx == NULL) {
34         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
35         return NULL;
36     }
37     (void)memset_s(poolCtx, sizeof(ENTROPY_SeedPool), 0, sizeof(ENTROPY_SeedPool));
38     poolCtx->esList = BSL_LIST_New(sizeof(ENTROPY_Source));
39     if (poolCtx->esList == NULL) {
40         BSL_SAL_Free(poolCtx);
41         BSL_ERR_PUSH_ERROR(BSL_LIST_MALLOC_FAIL);
42         return NULL;
43     }
44     poolCtx->minEntropy = SEEDPOOL_ES_INIT_MINENTROPY;
45     if (isCreateNullPool) {
46         return poolCtx;
47     }
48     CRYPT_EAL_EsPara para = {false, SEEDPOOL_ES_SYS_MINENTROPY, NULL, ENTROPY_SysEntropyGet};
49     int32_t ret = ENTROPY_SeedPoolAddEs(poolCtx, &para);
50     if (ret != CRYPT_SUCCESS) {
51         ENTROPY_SeedPoolFree(poolCtx);
52         BSL_ERR_PUSH_ERROR(ret);
53         return NULL;
54     }
55     CRYPT_EAL_EsPara hwPara = {true, SEEDPOOL_ES_FULL_MINENTROPY, NULL, ENTROPY_HWEntropyGet};
56     ret = ENTROPY_SeedPoolAddEs(poolCtx, &hwPara);
57     if (ret != CRYPT_SUCCESS) {
58         ENTROPY_SeedPoolFree(poolCtx);
59         BSL_ERR_PUSH_ERROR(ret);
60         return NULL;
61     }
62     return poolCtx;
63 }
64 
SeedPoolEsNew(const CRYPT_EAL_EsPara * para)65 static ENTROPY_Source *SeedPoolEsNew(const CRYPT_EAL_EsPara *para)
66 {
67     ENTROPY_Source *es = BSL_SAL_Malloc(sizeof(ENTROPY_Source));
68     if (es == NULL) {
69         BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
70         return NULL;
71     }
72     es->isPhysical = para->isPhysical;
73     es->minEntropy = para->minEntropy;
74     es->ctx = para->entropyCtx;
75     es->entropyGet = (EntropyGet)(para->entropyGet);
76     return es;
77 }
78 
ENTROPY_SeedPoolAddEs(ENTROPY_SeedPool * pool,const CRYPT_EAL_EsPara * para)79 int32_t ENTROPY_SeedPoolAddEs(ENTROPY_SeedPool *pool, const CRYPT_EAL_EsPara *para)
80 {
81     if (pool == NULL) {
82         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
83         return CRYPT_NULL_INPUT;
84     }
85 
86     if (BSL_LIST_COUNT(pool->esList) >= SEEDPOOL_ES_MAX_SIZE) {
87         BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_ES_LIST_FULL);
88         return CRYPT_SEED_POOL_ES_LIST_FULL;
89     }
90     ENTROPY_Source *es = SeedPoolEsNew(para);
91     if (es == NULL) {
92         BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NEW_ERROR);
93         return CRYPT_SEED_POOL_NEW_ERROR;
94     }
95     /*
96      * The header insertion method is used to add an entropy source to ensure that the entropy source added by the
97      * invoker is used first when the entropy data is obtained.
98      */
99     int32_t ret = BSL_LIST_AddElement(pool->esList, es, BSL_LIST_POS_BEFORE);
100     if (ret != CRYPT_SUCCESS) {
101         BSL_SAL_Free(es);
102         BSL_ERR_PUSH_ERROR(ret);
103         return ret;
104     }
105     pool->minEntropy = (pool->minEntropy < para->minEntropy) ? pool->minEntropy : para->minEntropy;
106     pool->isContainFes = pool->isContainFes || (para->minEntropy == SEEDPOOL_ES_FULL_MINENTROPY);
107     pool->isContainPes = pool->isContainPes || para->isPhysical;
108     return CRYPT_SUCCESS;
109 }
110 
ENTROPY_SeedPoolFree(ENTROPY_SeedPool * pool)111 void ENTROPY_SeedPoolFree(ENTROPY_SeedPool *pool)
112 {
113     if (pool == NULL) {
114         return;
115     }
116 
117     if (pool->esList != NULL) {
118         BSL_LIST_FREE(pool->esList, BSL_SAL_Free);
119     }
120     BSL_SAL_Free(pool);
121     return;
122 }
123 
GetMinLen(uint32_t needEntropy,uint32_t currEntropy,uint32_t minEntropy,uint32_t bufLen)124 static uint32_t GetMinLen(uint32_t needEntropy, uint32_t currEntropy, uint32_t minEntropy, uint32_t bufLen)
125 {
126     if (needEntropy == 0) {
127         return bufLen;
128     }
129     uint32_t len =
130         (uint32_t)(((uint64_t)(needEntropy - currEntropy) + (uint64_t)minEntropy - 1) / (uint64_t)minEntropy);
131     return bufLen >= len ? len : bufLen;
132 }
133 
134 
ENTROPY_SeedPoolCollect(ENTROPY_SeedPool * pool,bool isNpesUsed,uint32_t needEntropy,uint8_t * data,uint32_t * len)135 uint32_t ENTROPY_SeedPoolCollect(ENTROPY_SeedPool *pool, bool isNpesUsed, uint32_t needEntropy, uint8_t *data,
136     uint32_t *len)
137 {
138     if (data == NULL || len == NULL) {
139         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
140         return 0;
141     }
142     if (!ENTROPY_SeedPoolCheckState(pool, isNpesUsed)) {
143         BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_STATE_ERROR);
144         return 0;
145     }
146     uint32_t bufLen = *len;
147     uint8_t *buf = data;
148     uint32_t curEntropy = 0;
149     for (ENTROPY_Source *es = BSL_LIST_GET_FIRST(pool->esList); es != NULL; es = BSL_LIST_GET_NEXT(pool->esList)) {
150         if (!isNpesUsed && !es->isPhysical) {
151             continue;
152         }
153         uint32_t tmpLen = GetMinLen(needEntropy, curEntropy, es->minEntropy, bufLen);
154         uint32_t readLen = es->entropyGet(es->ctx, buf, tmpLen);
155         if (readLen > 0) {
156             bufLen -= readLen;
157             buf += readLen;
158             curEntropy += es->minEntropy * readLen;
159         }
160         bool flag = (needEntropy == 0) ? (bufLen == 0) : (curEntropy >= needEntropy);
161         if (flag) {
162             break;
163         }
164     }
165     *len = buf - data;
166     return curEntropy;
167 }
168 
ENTROPY_SeedPoolCheckState(ENTROPY_SeedPool * seedPool,bool isNpesUsed)169 bool ENTROPY_SeedPoolCheckState(ENTROPY_SeedPool *seedPool, bool isNpesUsed)
170 {
171     if (seedPool == NULL) {
172         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
173         return false;
174     }
175     if (BSL_LIST_COUNT(seedPool->esList) == 0) {
176         BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NO_ENTROPY_SOURCE);
177         return false;
178     }
179     if (!isNpesUsed && !seedPool->isContainPes) {
180         BSL_ERR_PUSH_ERROR(CRYPT_SEED_POOL_NO_ENTROPY_SOURCE);
181         return false;
182     }
183     return true;
184 }
185 
ENTROPY_SeedPoolGetMinEntropy(ENTROPY_SeedPool * seedPool)186 uint32_t ENTROPY_SeedPoolGetMinEntropy(ENTROPY_SeedPool *seedPool)
187 {
188     if (seedPool == NULL) {
189         BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
190         return 0;
191     }
192     return seedPool->minEntropy;
193 }
194 #endif