• 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 #if defined(HITLS_CRYPTO_ENTROPY) && defined(HITLS_CRYPTO_ENTROPY_SYS)
18 
19 #include <stdint.h>
20 #include <time.h>
21 #include "securec.h"
22 #include "bsl_err_internal.h"
23 #include "crypt_errno.h"
24 #include "es_noise_source.h"
25 
26 
27 /**
28  * Binary WINDOW 1024, 0.8 Entropy CUT off 664 0.6 Entropy CUT off 748
29  * reference to SP800-90B sec 4.4.2
30  */
31 #define NS_APT_BIN_CUT_OFF 592
32 #define NS_APT_BIN_WINDOW_SIZE 1024
33 
34 /**
35  * C = 1 + ceil(-log_2(alpha)/H), H = 1(MIN_ENTROPY), alpha = 2^(-20)
36  * alpha value reference SP800-90B sec 4.4.1
37  * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 20.
38  */
39 #define NS_RCT_CUT_OFF 20  // max 20
40 
41 #define NS_ENTROPY_HASH_SIZE 32                            // hash size
42 #define NS_ENTROPY_DATA_SIZE (NS_ENTROPY_HASH_SIZE * 4)  // 4 * 32, 128 bytes,1024 bits,one APT window
43 
44 /* Mainstream CPU cache access unit (cache line) 32 或者64 */
45 #define NS_CACHE_LINE_SIZE 64                                         // memory column Size
46 #define NS_CACHE_LINE_COUNT 1025                                      // memory row Size
47 #define NS_CACHE_SIZE (NS_CACHE_LINE_SIZE * NS_CACHE_LINE_COUNT)      // total operation memory size
48 #define NS_CACHE_MIN_SIZE 33                                          // minimum Length
49 
50 #define NS_ENTROPY_RCT_FAILURE (-1)
51 #define NS_ENTROPY_APT_FAILURE (-2)
52 
53 #define NS_ENTROPY_MAX_LIFE 30       // maximum lifetime of entropy data: 30 seconds
54 
55 typedef struct ES_JitterState {
56     int8_t testFailure;
57     uint8_t rctCount;
58     uint8_t aptBase;
59     uint8_t aptBaseSet;
60     uint16_t aptCount;
61     uint16_t aptObservations;
62     uint8_t data[NS_ENTROPY_DATA_SIZE];
63     uint64_t lastDelta;
64     uint32_t remainCount;
65     uint32_t memLocation;
66     uint8_t mem[NS_CACHE_LINE_COUNT][NS_CACHE_LINE_SIZE];
67     volatile uint32_t mID;
68     uint64_t lastTime;
69     void (*hashFunc)(uint8_t *, int, uint8_t *, int);
70 } ES_JitterState;
71 
UpdateRctHealth(ES_JitterState * e,int stuck)72 static void UpdateRctHealth(ES_JitterState *e, int stuck)
73 {
74     if (e->rctCount > NS_RCT_CUT_OFF) {
75         return;
76     }
77     if (stuck > 0) {
78         e->rctCount++;
79         if (e->rctCount > NS_RCT_CUT_OFF) {
80             e->testFailure = NS_ENTROPY_RCT_FAILURE;  // If the RCT test fails, the entropy source can be restarted.
81         }
82     } else {
83         e->rctCount = 0;
84     }
85 }
UpdateAptHealth(ES_JitterState * e,uint8_t data)86 static void UpdateAptHealth(ES_JitterState *e, uint8_t data)
87 {
88     if (e->aptBaseSet == 0) {
89         e->aptBase = data;
90         e->aptBaseSet = 1;
91         e->aptCount = 1;
92         e->aptObservations = 1;
93         return;
94     }
95     if (e->aptBase == data) {
96         e->aptCount++;
97         if (e->aptCount > NS_APT_BIN_CUT_OFF) {
98             e->testFailure = NS_ENTROPY_APT_FAILURE;  // If APT detection fails, the entropy source can be restarted.
99         }
100     }
101     e->aptObservations++;
102     if (e->aptObservations >= NS_APT_BIN_WINDOW_SIZE) {
103         e->aptBaseSet = 0;
104     }
105 }
106 
NS_ENTROPY_Gettick(void)107 static uint64_t NS_ENTROPY_Gettick(void)
108 {
109     uint64_t ticks = 0;
110     struct timespec time;
111     if (clock_gettime(CLOCK_REALTIME, &time) == 0) {
112         ticks = ((uint64_t)time.tv_sec & 0xFFFFFFFF) * 1000000000UL;
113         ticks = ticks + (uint64_t)time.tv_nsec;
114     }
115     return ticks;
116 }
117 
118 #define NS_MOVE_LEVEL 128
119 
EntropyMemeryAccess(ES_JitterState * e,uint8_t det)120 static void __attribute__((optimize("O0"))) EntropyMemeryAccess(ES_JitterState *e, uint8_t det)
121 {
122     /*
123      * 1. Random read/write start position
124      * 2. Read and write position change by position value
125      * 3. Multiple data reads and writes
126      * 4. branch prediction mitigation
127      */
128     e->mID = (e->mID + det) % NS_CACHE_SIZE;
129     uint32_t bound = NS_CACHE_LINE_COUNT + det;
130     for (uint32_t i = 0; i < bound; i++) {
131         // c, l Calculate the row and column coordinate points.
132         uint32_t c = e->mID / NS_CACHE_LINE_SIZE;
133         uint32_t l = e->mID % NS_CACHE_LINE_SIZE;
134         volatile uint8_t *volatile cur = e->mem[c] + l;
135         *cur ^= det;
136         e->memLocation = (e->memLocation + (*cur & 0x0f) + NS_CACHE_MIN_SIZE) % NS_CACHE_SIZE;
137     }
138 }
139 
140 /**
141  * Get a random position: keep moving right until there is a non-zero bit in the lower eight bits,
142  * then return the lower eight bits
143  */
GetUChar(uint64_t tick)144 static uint8_t GetUChar(uint64_t tick)
145 {
146     size_t i;
147     volatile uint64_t data = tick;
148     for (i = 0; i < sizeof(uint64_t); i++) {
149         if ((data & 1) == 1) {
150             return (uint8_t)data;
151         }
152         data >>= 1;
153     }
154     return (uint8_t)((data % NS_CACHE_LINE_SIZE) + NS_CACHE_MIN_SIZE);
155 }
156 
EntropyMeasure(ES_JitterState * e,int32_t index)157 static void EntropyMeasure(ES_JitterState *e, int32_t index)
158 {
159     uint8_t data = 0;
160     int i;
161     // One byte has eight bits. Only the status of one bit can be obtained each time the memory is read or written.
162     for (i = 0; i < 8; i++) {  // 8 bit
163         uint64_t tick1 = NS_ENTROPY_Gettick();
164         EntropyMemeryAccess(e, GetUChar(tick1));
165         uint64_t tick = NS_ENTROPY_Gettick();
166         uint64_t delta = tick - tick1;
167         uint8_t bit;
168         if (delta & 0x01) {
169             bit = (delta >> 3) & 0x01; // 3:4th bits
170         } else {
171             bit = (delta >> 7) & 0x01; // 7:8th bits
172         }
173         data = (uint8_t)(data << 1); // Move to the left first to prevent entropy overflow.
174         data |= bit;
175         UpdateRctHealth(e, e->lastDelta == bit);
176         UpdateAptHealth(e, bit);
177         e->lastDelta = bit;
178     }
179 
180     e->data[index] = data;
181     data = 0;  // clean
182 }
183 
EntropyProcess(ES_JitterState * e)184 static void EntropyProcess(ES_JitterState *e)
185 {
186     int32_t i, start;
187     uint8_t buf[NS_ENTROPY_HASH_SIZE + 1];
188     for (i = 0; i < NS_ENTROPY_DATA_SIZE; i++) {
189         EntropyMeasure(e, i);  // Obtains 1-byte entropy.
190         start = (i / NS_ENTROPY_HASH_SIZE) * NS_ENTROPY_HASH_SIZE;
191         /**
192          * Copy 32 bytes to buf at a time, but only one byte of entropy is added to e-data in each loop. Subsequently,
193          * the latest entropy is attached to the tail of the buffer each time, and the 33-byte content is hashed.
194          * The hashed content is written to the internal entropy pool of the entropy source.
195          */
196         (void)memcpy_s(buf, NS_ENTROPY_HASH_SIZE + 1, e->data + start, NS_ENTROPY_HASH_SIZE);
197         // The latest entropy 1 byte is placed at the end. The 33-byte data is hashed to form a new 32-byte entropy.
198         buf[NS_ENTROPY_HASH_SIZE] = e->data[i];
199         e->hashFunc(buf, sizeof(buf), (e->data + start), NS_ENTROPY_HASH_SIZE);
200     }
201     (void)memset_s(buf, sizeof(buf), 0, sizeof(buf));
202 }
203 
EsCpuJitterGen(ES_JitterState * jitter,uint8_t * buf,uint32_t bufLen)204 static int32_t EsCpuJitterGen(ES_JitterState *jitter, uint8_t *buf, uint32_t bufLen)
205 {
206     const uint32_t entropySize = sizeof(jitter->data);
207     EntropyProcess(jitter);
208     uint8_t *out = buf;
209     uint32_t left = bufLen;
210     while (left > 0) {
211         EntropyProcess(jitter);  // 1024
212         if (jitter->testFailure != CRYPT_SUCCESS) {
213             jitter->remainCount = 0;
214             break;
215         }
216         uint32_t length = left > entropySize ? entropySize : left;
217         (void)memcpy_s(out, length, jitter->data, length);
218         left -= length;
219         if (left <= 0) {
220             jitter->remainCount = entropySize - length;
221             jitter->lastTime = BSL_SAL_CurrentSysTimeGet();
222             break;
223         }
224         out += length;
225     }
226     return jitter->testFailure;
227 }
228 
EsCpuJitterGet(ES_JitterState * jitter,uint8_t * buf,uint32_t bufLen)229 static uint32_t EsCpuJitterGet(ES_JitterState *jitter, uint8_t *buf, uint32_t bufLen)
230 {
231     if (jitter->remainCount == 0) {
232         return bufLen;
233     }
234     uint64_t nowTime = BSL_SAL_CurrentSysTimeGet();
235     if (nowTime == 0 || nowTime - jitter->lastTime > NS_ENTROPY_MAX_LIFE) {
236         return bufLen;
237     }
238     uint32_t length = (bufLen < jitter->remainCount) ? bufLen : jitter->remainCount;
239     (void)memcpy_s(buf, bufLen, jitter->data + (NS_ENTROPY_DATA_SIZE - jitter->remainCount), length);
240     jitter->remainCount -= length;
241     return bufLen - length;
242 }
243 
ES_CpuJitterRead(void * ctx,uint32_t timeout,uint8_t * buf,uint32_t bufLen)244 static int32_t ES_CpuJitterRead(void *ctx, uint32_t timeout, uint8_t *buf, uint32_t bufLen)
245 {
246     ES_JitterState *jitter = (ES_JitterState *)ctx;
247     (void)timeout;
248     if (ctx == NULL || buf == NULL || bufLen <= 0) {
249         return CRYPT_NULL_INPUT;
250     }
251     uint32_t left = EsCpuJitterGet(jitter, buf, bufLen);
252     if (left == 0) {
253         return CRYPT_SUCCESS;
254     }
255     return EsCpuJitterGen(jitter, buf + (bufLen -left), left);
256 }
257 
ES_CpuJitterFree(void * ctx)258 static void ES_CpuJitterFree(void *ctx)
259 {
260     if (ctx == NULL) {
261         return;
262     }
263     (void)memset_s(ctx, sizeof(ES_JitterState), 0, sizeof(ES_JitterState));
264     BSL_SAL_FREE(ctx);
265 }
266 
ES_CpuJitterInit(void * para)267 static void *ES_CpuJitterInit(void *para)
268 {
269     if (para == NULL) {
270         return NULL;
271     }
272     ES_JitterState *e = (ES_JitterState *)BSL_SAL_Malloc(sizeof(ES_JitterState));
273     if (e == NULL) {
274         return NULL;
275     }
276     e->rctCount = 0;
277     e->aptBaseSet = 0;
278     e->mID = 0;
279     e->hashFunc = para;
280     e->testFailure = CRYPT_SUCCESS;
281     // Try to read 32 bytes once to check whether the environment is normal.
282     uint8_t data[32] = {0};
283     if (ES_CpuJitterRead(e, true, data, sizeof(data)) != CRYPT_SUCCESS) {
284         (void)memset_s(data, sizeof(data), 0, 32);  // 32, Zeroed 32-byte array
285         ES_CpuJitterFree(e);
286         return NULL;
287     }
288     return e;
289 }
290 
291 
EmptyConditionComp(uint8_t * out,int32_t outLen,uint8_t * in,int32_t inLen)292 static void EmptyConditionComp(uint8_t *out, int32_t outLen, uint8_t *in, int32_t inLen)
293 {
294     (void)out;
295     (void)outLen;
296     (void)in;
297     (void)inLen;
298 }
299 
ES_CpuJitterGetCtx(void)300 ES_NoiseSource *ES_CpuJitterGetCtx(void)
301 {
302     ES_NoiseSource *ctx = BSL_SAL_Malloc(sizeof(ES_NoiseSource));
303     if (ctx == NULL) {
304         BSL_ERR_PUSH_ERROR(BSL_LIST_MALLOC_FAIL);
305         return NULL;
306     }
307     (void)memset_s(ctx, sizeof(ES_NoiseSource), 0, sizeof(ES_NoiseSource));
308     uint32_t len = strlen("CPU-Jitter");
309     ctx->name = BSL_SAL_Malloc(len + 1);
310     if (ctx->name == NULL) {
311         BSL_SAL_Free(ctx);
312         BSL_ERR_PUSH_ERROR(BSL_LIST_MALLOC_FAIL);
313         return NULL;
314     }
315     (void)strncpy_s(ctx->name, len + 1, "CPU-Jitter", len);
316     ctx->autoTest = true;
317     ctx->para = (void *)EmptyConditionComp;
318     ctx->init = ES_CpuJitterInit;
319     ctx->read = ES_CpuJitterRead;
320     ctx->deinit = ES_CpuJitterFree;
321     ctx->minEntropy = 5; // one byte bring 5 bits entropy
322     return ctx;
323 }
324 #endif