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