dualcone 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,281 @@
1
+ #define hydro_pwhash_ENC_ALGBYTES 1
2
+ #define hydro_pwhash_HASH_ALGBYTES 1
3
+ #define hydro_pwhash_THREADSBYTES 1
4
+ #define hydro_pwhash_OPSLIMITBYTES 8
5
+ #define hydro_pwhash_MEMLIMITBYTES 8
6
+ #define hydro_pwhash_HASHBYTES 32
7
+ #define hydro_pwhash_SALTBYTES 16
8
+ #define hydro_pwhash_PARAMSBYTES \
9
+ (hydro_pwhash_HASH_ALGBYTES + hydro_pwhash_THREADSBYTES + hydro_pwhash_OPSLIMITBYTES + \
10
+ hydro_pwhash_MEMLIMITBYTES + hydro_pwhash_SALTBYTES + hydro_pwhash_HASHBYTES)
11
+ #define hydro_pwhash_ENC_ALG 0x01
12
+ #define hydro_pwhash_HASH_ALG 0x01
13
+ #define hydro_pwhash_CONTEXT "hydro_pw"
14
+
15
+ static int
16
+ _hydro_pwhash_hash(uint8_t out[hydro_random_SEEDBYTES], size_t h_len,
17
+ const uint8_t salt[hydro_pwhash_SALTBYTES], const char *passwd,
18
+ size_t passwd_len, const char ctx[hydro_pwhash_CONTEXTBYTES],
19
+ const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit,
20
+ size_t memlimit, uint8_t threads)
21
+ {
22
+ _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES];
23
+ hydro_hash_state h_st;
24
+ uint8_t tmp64_u8[8];
25
+ uint64_t i;
26
+ uint8_t tmp8;
27
+
28
+ COMPILER_ASSERT(hydro_pwhash_MASTERKEYBYTES >= hydro_hash_KEYBYTES);
29
+ hydro_hash_init(&h_st, ctx, master_key);
30
+
31
+ STORE64_LE(tmp64_u8, (uint64_t) passwd_len);
32
+ hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);
33
+ hydro_hash_update(&h_st, passwd, passwd_len);
34
+
35
+ hydro_hash_update(&h_st, salt, hydro_pwhash_SALTBYTES);
36
+
37
+ tmp8 = hydro_pwhash_HASH_ALG;
38
+ hydro_hash_update(&h_st, &tmp8, 1);
39
+
40
+ hydro_hash_update(&h_st, &threads, 1);
41
+
42
+ STORE64_LE(tmp64_u8, (uint64_t) memlimit);
43
+ hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);
44
+
45
+ STORE64_LE(tmp64_u8, (uint64_t) h_len);
46
+ hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);
47
+
48
+ hydro_hash_final(&h_st, (uint8_t *) (void *) &state, sizeof state);
49
+
50
+ gimli_core_u8(state, 1);
51
+ COMPILER_ASSERT(gimli_RATE >= 8);
52
+ for (i = 0; i < opslimit; i++) {
53
+ mem_zero(state, gimli_RATE);
54
+ STORE64_LE(state, i);
55
+ gimli_core_u8(state, 0);
56
+ }
57
+ mem_zero(state, gimli_RATE);
58
+
59
+ COMPILER_ASSERT(hydro_random_SEEDBYTES == gimli_CAPACITY);
60
+ memcpy(out, state + gimli_RATE, hydro_random_SEEDBYTES);
61
+ hydro_memzero(state, sizeof state);
62
+
63
+ return 0;
64
+ }
65
+
66
+ void
67
+ hydro_pwhash_keygen(uint8_t master_key[hydro_pwhash_MASTERKEYBYTES])
68
+ {
69
+ hydro_random_buf(master_key, hydro_pwhash_MASTERKEYBYTES);
70
+ }
71
+
72
+ int
73
+ hydro_pwhash_deterministic(uint8_t *h, size_t h_len, const char *passwd, size_t passwd_len,
74
+ const char ctx[hydro_pwhash_CONTEXTBYTES],
75
+ const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit,
76
+ size_t memlimit, uint8_t threads)
77
+ {
78
+ uint8_t seed[hydro_random_SEEDBYTES];
79
+
80
+ COMPILER_ASSERT(sizeof zero >= hydro_pwhash_SALTBYTES);
81
+ COMPILER_ASSERT(sizeof zero >= hydro_pwhash_MASTERKEYBYTES);
82
+
83
+ (void) memlimit;
84
+ if (_hydro_pwhash_hash(seed, h_len, zero, passwd, passwd_len, ctx, master_key, opslimit,
85
+ memlimit, threads) != 0) {
86
+ return -1;
87
+ }
88
+ hydro_random_buf_deterministic(h, h_len, seed);
89
+ hydro_memzero(seed, sizeof seed);
90
+
91
+ return 0;
92
+ }
93
+
94
+ int
95
+ hydro_pwhash_create(uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd, size_t passwd_len,
96
+ const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit,
97
+ size_t memlimit, uint8_t threads)
98
+ {
99
+ uint8_t *const enc_alg = &stored[0];
100
+ uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES];
101
+ uint8_t *const hash_alg = &secretbox[hydro_secretbox_HEADERBYTES];
102
+ uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES];
103
+ uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES];
104
+ uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES];
105
+ uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES];
106
+ uint8_t *const h = &salt[hydro_pwhash_SALTBYTES];
107
+
108
+ COMPILER_ASSERT(hydro_pwhash_STOREDBYTES >= hydro_pwhash_ENC_ALGBYTES +
109
+ hydro_secretbox_HEADERBYTES +
110
+ hydro_pwhash_PARAMSBYTES);
111
+ (void) memlimit;
112
+ mem_zero(stored, hydro_pwhash_STOREDBYTES);
113
+ *enc_alg = hydro_pwhash_ENC_ALG;
114
+ *hash_alg = hydro_pwhash_HASH_ALG;
115
+ *threads_u8 = threads;
116
+ STORE64_LE(opslimit_u8, opslimit);
117
+ STORE64_LE(memlimit_u8, (uint64_t) memlimit);
118
+ hydro_random_buf(salt, hydro_pwhash_SALTBYTES);
119
+
120
+ COMPILER_ASSERT(sizeof zero >= hydro_pwhash_MASTERKEYBYTES);
121
+ if (_hydro_pwhash_hash(h, hydro_pwhash_HASHBYTES, salt, passwd, passwd_len,
122
+ hydro_pwhash_CONTEXT, zero, opslimit, memlimit, threads) != 0) {
123
+ return -1;
124
+ }
125
+ COMPILER_ASSERT(hydro_pwhash_MASTERKEYBYTES == hydro_secretbox_KEYBYTES);
126
+
127
+ return hydro_secretbox_encrypt(secretbox, hash_alg, hydro_pwhash_PARAMSBYTES,
128
+ (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key);
129
+ }
130
+
131
+ static int
132
+ _hydro_pwhash_verify(uint8_t computed_h[hydro_pwhash_HASHBYTES],
133
+ const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd,
134
+ size_t passwd_len, const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES],
135
+ uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max)
136
+ {
137
+ const uint8_t *const enc_alg = &stored[0];
138
+ const uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES];
139
+
140
+ uint8_t params[hydro_pwhash_PARAMSBYTES];
141
+ uint8_t *const hash_alg = &params[0];
142
+ uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES];
143
+ uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES];
144
+ uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES];
145
+ uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES];
146
+ uint8_t *const h = &salt[hydro_pwhash_SALTBYTES];
147
+
148
+ uint64_t opslimit;
149
+ size_t memlimit;
150
+ uint8_t threads;
151
+
152
+ (void) memlimit;
153
+ if (*enc_alg != hydro_pwhash_ENC_ALG) {
154
+ return -1;
155
+ }
156
+ if (hydro_secretbox_decrypt(params, secretbox,
157
+ hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES,
158
+ (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key) != 0) {
159
+ return -1;
160
+ }
161
+ if (*hash_alg != hydro_pwhash_HASH_ALG || (opslimit = LOAD64_LE(opslimit_u8)) > opslimit_max ||
162
+ (memlimit = (size_t) LOAD64_LE(memlimit_u8)) > memlimit_max ||
163
+ (threads = *threads_u8) > threads_max) {
164
+ return -1;
165
+ }
166
+ if (_hydro_pwhash_hash(computed_h, hydro_pwhash_HASHBYTES, salt, passwd, passwd_len,
167
+ hydro_pwhash_CONTEXT, zero, opslimit, memlimit, threads) == 0 &&
168
+ hydro_equal(computed_h, h, hydro_pwhash_HASHBYTES) == 1) {
169
+ return 0;
170
+ }
171
+ return -1;
172
+ }
173
+
174
+ int
175
+ hydro_pwhash_verify(const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd,
176
+ size_t passwd_len, const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES],
177
+ uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max)
178
+ {
179
+ uint8_t computed_h[hydro_pwhash_HASHBYTES];
180
+ int ret;
181
+
182
+ ret = _hydro_pwhash_verify(computed_h, stored, passwd, passwd_len, master_key, opslimit_max,
183
+ memlimit_max, threads_max);
184
+ hydro_memzero(computed_h, sizeof computed_h);
185
+
186
+ return ret;
187
+ }
188
+
189
+ int
190
+ hydro_pwhash_derive_static_key(uint8_t *static_key, size_t static_key_len,
191
+ const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd,
192
+ size_t passwd_len, const char ctx[hydro_pwhash_CONTEXTBYTES],
193
+ const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES],
194
+ uint64_t opslimit_max, size_t memlimit_max, uint8_t threads_max)
195
+ {
196
+ uint8_t computed_h[hydro_pwhash_HASHBYTES];
197
+
198
+ if (_hydro_pwhash_verify(computed_h, stored, passwd, passwd_len, master_key, opslimit_max,
199
+ memlimit_max, threads_max) != 0) {
200
+ hydro_memzero(computed_h, sizeof computed_h);
201
+ return -1;
202
+ }
203
+ COMPILER_ASSERT(hydro_kdf_CONTEXTBYTES <= hydro_pwhash_CONTEXTBYTES);
204
+ COMPILER_ASSERT(hydro_kdf_KEYBYTES <= hydro_pwhash_HASHBYTES);
205
+ hydro_kdf_derive_from_key(static_key, static_key_len, 0, ctx, computed_h);
206
+ hydro_memzero(computed_h, sizeof computed_h);
207
+
208
+ return 0;
209
+ }
210
+
211
+ int
212
+ hydro_pwhash_reencrypt(uint8_t stored[hydro_pwhash_STOREDBYTES],
213
+ const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES],
214
+ const uint8_t new_master_key[hydro_pwhash_MASTERKEYBYTES])
215
+ {
216
+ uint8_t *const enc_alg = &stored[0];
217
+ uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES];
218
+ uint8_t *const params = &secretbox[hydro_secretbox_HEADERBYTES];
219
+
220
+ if (*enc_alg != hydro_pwhash_ENC_ALG) {
221
+ return -1;
222
+ }
223
+ if (hydro_secretbox_decrypt(secretbox, secretbox,
224
+ hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES,
225
+ (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key) != 0) {
226
+ return -1;
227
+ }
228
+ memmove(params, secretbox, hydro_pwhash_PARAMSBYTES);
229
+ return hydro_secretbox_encrypt(secretbox, params, hydro_pwhash_PARAMSBYTES, (uint64_t) *enc_alg,
230
+ hydro_pwhash_CONTEXT, new_master_key);
231
+ }
232
+
233
+ int
234
+ hydro_pwhash_upgrade(uint8_t stored[hydro_pwhash_STOREDBYTES],
235
+ const uint8_t master_key[hydro_pwhash_MASTERKEYBYTES], uint64_t opslimit,
236
+ size_t memlimit, uint8_t threads)
237
+ {
238
+ uint8_t *const enc_alg = &stored[0];
239
+ uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES];
240
+ uint8_t *const params = &secretbox[hydro_secretbox_HEADERBYTES];
241
+ uint8_t *const hash_alg = &params[0];
242
+ uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES];
243
+ uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES];
244
+ uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES];
245
+ uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES];
246
+ uint8_t *const h = &salt[hydro_pwhash_SALTBYTES];
247
+
248
+ _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES];
249
+ uint64_t i;
250
+ uint64_t opslimit_prev;
251
+
252
+ if (*enc_alg != hydro_pwhash_ENC_ALG) {
253
+ return -1;
254
+ }
255
+ if (hydro_secretbox_decrypt(secretbox, secretbox,
256
+ hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES,
257
+ (uint64_t) *enc_alg, hydro_pwhash_CONTEXT, master_key) != 0) {
258
+ return -1;
259
+ }
260
+ memmove(params, secretbox, hydro_pwhash_PARAMSBYTES);
261
+ opslimit_prev = LOAD64_LE(opslimit_u8);
262
+ if (*hash_alg != hydro_pwhash_HASH_ALG) {
263
+ mem_zero(stored, hydro_pwhash_STOREDBYTES);
264
+ return -1;
265
+ }
266
+ COMPILER_ASSERT(hydro_random_SEEDBYTES == gimli_CAPACITY);
267
+ memcpy(state + gimli_RATE, h, hydro_random_SEEDBYTES);
268
+ for (i = opslimit_prev; i < opslimit; i++) {
269
+ mem_zero(state, gimli_RATE);
270
+ STORE64_LE(state, i);
271
+ gimli_core_u8(state, 0);
272
+ }
273
+ mem_zero(state, gimli_RATE);
274
+ memcpy(h, state + gimli_RATE, hydro_random_SEEDBYTES);
275
+ *threads_u8 = threads;
276
+ STORE64_LE(opslimit_u8, opslimit);
277
+ STORE64_LE(memlimit_u8, (uint64_t) memlimit);
278
+
279
+ return hydro_secretbox_encrypt(secretbox, params, hydro_pwhash_PARAMSBYTES, (uint64_t) *enc_alg,
280
+ hydro_pwhash_CONTEXT, master_key);
281
+ }
@@ -0,0 +1,465 @@
1
+ static TLS struct {
2
+ _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES];
3
+ uint64_t counter;
4
+ uint8_t initialized;
5
+ uint8_t available;
6
+ } hydro_random_context;
7
+
8
+ #if defined(AVR) && !defined(__unix__)
9
+ #include <Arduino.h>
10
+
11
+ static bool
12
+ hydro_random_rbit(uint16_t x)
13
+ {
14
+ uint8_t x8;
15
+
16
+ x8 = ((uint8_t)(x >> 8)) ^ (uint8_t) x;
17
+ x8 = (x8 >> 4) ^ (x8 & 0xf);
18
+ x8 = (x8 >> 2) ^ (x8 & 0x3);
19
+ x8 = (x8 >> 1) ^ x8;
20
+
21
+ return (bool) (x8 & 1);
22
+ }
23
+
24
+ static int
25
+ hydro_random_init(void)
26
+ {
27
+ const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' };
28
+ hydro_hash_state st;
29
+ uint16_t ebits = 0;
30
+ uint16_t tc;
31
+ bool a, b;
32
+
33
+ cli();
34
+ MCUSR = 0;
35
+ WDTCSR |= _BV(WDCE) | _BV(WDE);
36
+ WDTCSR = _BV(WDIE);
37
+ sei();
38
+
39
+ hydro_hash_init(&st, ctx, NULL);
40
+
41
+ while (ebits < 256) {
42
+ delay(1);
43
+ tc = TCNT1;
44
+ hydro_hash_update(&st, (const uint8_t *) &tc, sizeof tc);
45
+ a = hydro_random_rbit(tc);
46
+ delay(1);
47
+ tc = TCNT1;
48
+ b = hydro_random_rbit(tc);
49
+ hydro_hash_update(&st, (const uint8_t *) &tc, sizeof tc);
50
+ if (a == b) {
51
+ continue;
52
+ }
53
+ hydro_hash_update(&st, (const uint8_t *) &b, sizeof b);
54
+ ebits++;
55
+ }
56
+
57
+ cli();
58
+ MCUSR = 0;
59
+ WDTCSR |= _BV(WDCE) | _BV(WDE);
60
+ WDTCSR = 0;
61
+ sei();
62
+
63
+ hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state);
64
+ hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state);
65
+
66
+ return 0;
67
+ }
68
+
69
+ ISR(WDT_vect) {}
70
+
71
+ #elif (defined(ESP32) || defined(ESP8266)) && !defined(__unix__)
72
+
73
+ // Important: RF *must* be activated on ESP board
74
+ // https://techtutorialsx.com/2017/12/22/esp32-arduino-random-number-generation/
75
+
76
+ #include <esp_system.h>
77
+
78
+ static int
79
+ hydro_random_init(void)
80
+ {
81
+ const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' };
82
+ hydro_hash_state st;
83
+ uint16_t ebits = 0;
84
+
85
+ hydro_hash_init(&st, ctx, NULL);
86
+
87
+ while (ebits < 256) {
88
+ uint32_t r = esp_random();
89
+
90
+ delay(10);
91
+ hydro_hash_update(&st, (const uint32_t *) &r, sizeof r);
92
+ ebits += 32;
93
+ }
94
+
95
+ hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state);
96
+ hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state);
97
+
98
+ return 0;
99
+ }
100
+
101
+ #elif defined(PARTICLE) && defined(PLATFORM_ID) && PLATFORM_ID > 2 && !defined(__unix__)
102
+
103
+ // Note: All particle platforms except for the Spark Core have a HW RNG. Only allow building on
104
+ // supported platforms for now. PLATFORM_ID definitions:
105
+ // https://github.com/particle-iot/device-os/blob/mesh-develop/hal/shared/platforms.h
106
+
107
+ #include "Particle.h"
108
+
109
+ static int
110
+ hydro_random_init(void)
111
+ {
112
+ const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' };
113
+ hydro_hash_state st;
114
+ uint16_t ebits = 0;
115
+
116
+ hydro_hash_init(&st, ctx, NULL);
117
+
118
+ while (ebits < 256) {
119
+ uint32_t r = HAL_RNG_GetRandomNumber();
120
+ hydro_hash_update(&st, (const uint32_t *) &r, sizeof r);
121
+ ebits += 32;
122
+ }
123
+
124
+ hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state);
125
+ hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state);
126
+
127
+ return 0;
128
+ }
129
+
130
+ #elif (defined(NRF52832_XXAA) || defined(NRF52832_XXAB)) && !defined(__unix__)
131
+
132
+ // Important: The SoftDevice *must* be activated to enable reading from the RNG
133
+ // http://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Frng.html
134
+
135
+ #include <nrf_soc.h>
136
+
137
+ static int
138
+ hydro_random_init(void)
139
+ {
140
+ const char ctx[hydro_hash_CONTEXTBYTES] = { 'h', 'y', 'd', 'r', 'o', 'P', 'R', 'G' };
141
+ hydro_hash_state st;
142
+ const uint8_t total_bytes = 32;
143
+ uint8_t remaining_bytes = total_bytes;
144
+ uint8_t available_bytes;
145
+ uint8_t rand_buffer[32];
146
+
147
+ hydro_hash_init(&st, ctx, NULL);
148
+
149
+ for (;;) {
150
+ if (sd_rand_application_bytes_available_get(&available_bytes) != NRF_SUCCESS) {
151
+ return -1;
152
+ }
153
+ if (available_bytes > 0) {
154
+ if (available_bytes > remaining_bytes) {
155
+ available_bytes = remaining_bytes;
156
+ }
157
+ if (sd_rand_application_vector_get(rand_buffer, available_bytes) != NRF_SUCCESS) {
158
+ return -1;
159
+ }
160
+ hydro_hash_update(&st, rand_buffer, total_bytes);
161
+ remaining_bytes -= available_bytes;
162
+ }
163
+ if (remaining_bytes <= 0) {
164
+ break;
165
+ }
166
+ delay(10);
167
+ }
168
+ hydro_hash_final(&st, hydro_random_context.state, sizeof hydro_random_context.state);
169
+ hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state);
170
+
171
+ return 0;
172
+ }
173
+
174
+ #elif defined(_WIN32)
175
+
176
+ #include <windows.h>
177
+ #define RtlGenRandom SystemFunction036
178
+ #if defined(__cplusplus)
179
+ extern "C"
180
+ #endif
181
+ BOOLEAN NTAPI
182
+ RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
183
+ #pragma comment(lib, "advapi32.lib")
184
+
185
+ static int
186
+ hydro_random_init(void)
187
+ {
188
+ if (!RtlGenRandom((PVOID) hydro_random_context.state,
189
+ (ULONG) sizeof hydro_random_context.state)) {
190
+ return -1;
191
+ }
192
+ hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state);
193
+
194
+ return 0;
195
+ }
196
+
197
+ #elif defined(__wasi__)
198
+
199
+ #include <unistd.h>
200
+
201
+ static int
202
+ hydro_random_init(void)
203
+ {
204
+ if (getentropy(hydro_random_context.state, sizeof hydro_random_context.state) != 0) {
205
+ return -1;
206
+ }
207
+ hydro_random_context.counter = ~LOAD64_LE(hydro_random_context.state);
208
+
209
+ return 0;
210
+ }
211
+
212
+ #elif defined(__unix__)
213
+
214
+ #include <errno.h>
215
+ #include <fcntl.h>
216
+ #ifdef __linux__
217
+ #include <poll.h>
218
+ #endif
219
+ #include <sys/types.h>
220
+ #include <unistd.h>
221
+
222
+ #ifdef __linux__
223
+ static int
224
+ hydro_random_block_on_dev_random(void)
225
+ {
226
+ struct pollfd pfd;
227
+ int fd;
228
+ int pret;
229
+
230
+ fd = open("/dev/random", O_RDONLY);
231
+ if (fd == -1) {
232
+ return 0;
233
+ }
234
+ pfd.fd = fd;
235
+ pfd.events = POLLIN;
236
+ pfd.revents = 0;
237
+ do {
238
+ pret = poll(&pfd, 1, -1);
239
+ } while (pret < 0 && (errno == EINTR || errno == EAGAIN));
240
+ if (pret != 1) {
241
+ (void) close(fd);
242
+ errno = EIO;
243
+ return -1;
244
+ }
245
+ return close(fd);
246
+ }
247
+ #endif
248
+
249
+ static ssize_t
250
+ hydro_random_safe_read(const int fd, void *const buf_, size_t len)
251
+ {
252
+ unsigned char *buf = (unsigned char *) buf_;
253
+ ssize_t readnb;
254
+
255
+ do {
256
+ while ((readnb = read(fd, buf, len)) < (ssize_t) 0 && (errno == EINTR || errno == EAGAIN)) {
257
+ }
258
+ if (readnb < (ssize_t) 0) {
259
+ return readnb;
260
+ }
261
+ if (readnb == (ssize_t) 0) {
262
+ break;
263
+ }
264
+ len -= (size_t) readnb;
265
+ buf += readnb;
266
+ } while (len > (ssize_t) 0);
267
+
268
+ return (ssize_t)(buf - (unsigned char *) buf_);
269
+ }
270
+
271
+ static int
272
+ hydro_random_init(void)
273
+ {
274
+ uint8_t tmp[gimli_BLOCKBYTES + 8];
275
+ int fd;
276
+ int ret = -1;
277
+
278
+ #ifdef __linux__
279
+ if (hydro_random_block_on_dev_random() != 0) {
280
+ return -1;
281
+ }
282
+ #endif
283
+ do {
284
+ fd = open("/dev/urandom", O_RDONLY);
285
+ if (fd == -1 && errno != EINTR) {
286
+ return -1;
287
+ }
288
+ } while (fd == -1);
289
+ if (hydro_random_safe_read(fd, tmp, sizeof tmp) == (ssize_t) sizeof tmp) {
290
+ memcpy(hydro_random_context.state, tmp, gimli_BLOCKBYTES);
291
+ memcpy(&hydro_random_context.counter, tmp + gimli_BLOCKBYTES, 8);
292
+ hydro_memzero(tmp, sizeof tmp);
293
+ ret = 0;
294
+ }
295
+ ret |= close(fd);
296
+
297
+ return ret;
298
+ }
299
+
300
+ #elif defined(TARGET_LIKE_MBED)
301
+
302
+ #include <mbedtls/ctr_drbg.h>
303
+ #include <mbedtls/entropy.h>
304
+
305
+ #if defined(MBEDTLS_ENTROPY_C)
306
+
307
+ static int
308
+ hydro_random_init(void)
309
+ {
310
+ mbedtls_entropy_context entropy;
311
+ uint16_t pos = 0;
312
+
313
+ mbedtls_entropy_init(&entropy);
314
+
315
+ // Pull data directly out of the entropy pool for the state, as it's small enough.
316
+ if (mbedtls_entropy_func(&entropy, (uint8_t *) &hydro_random_context.counter,
317
+ sizeof hydro_random_context.counter) != 0) {
318
+ return -1;
319
+ }
320
+ // mbedtls_entropy_func can't provide more than MBEDTLS_ENTROPY_BLOCK_SIZE in one go.
321
+ // This constant depends of mbedTLS configuration (whether the PRNG is backed by SHA256/SHA512
322
+ // at this time) Therefore, if necessary, we get entropy multiple times.
323
+
324
+ do {
325
+ const uint8_t dataLeftToConsume = gimli_BLOCKBYTES - pos;
326
+ const uint8_t currentChunkSize = (dataLeftToConsume > MBEDTLS_ENTROPY_BLOCK_SIZE)
327
+ ? MBEDTLS_ENTROPY_BLOCK_SIZE
328
+ : dataLeftToConsume;
329
+
330
+ // Forces mbedTLS to fetch fresh entropy, then get some to feed libhydrogen.
331
+ if (mbedtls_entropy_gather(&entropy) != 0 ||
332
+ mbedtls_entropy_func(&entropy, &hydro_random_context.state[pos], currentChunkSize) !=
333
+ 0) {
334
+ return -1;
335
+ }
336
+ pos += MBEDTLS_ENTROPY_BLOCK_SIZE;
337
+ } while (pos < gimli_BLOCKBYTES);
338
+
339
+ mbedtls_entropy_free(&entropy);
340
+
341
+ return 0;
342
+ }
343
+
344
+ #else
345
+ #error Need an entropy source
346
+ #endif
347
+
348
+ #else
349
+ #error Unsupported platform
350
+ #endif
351
+
352
+ static void
353
+ hydro_random_check_initialized(void)
354
+ {
355
+ if (hydro_random_context.initialized == 0) {
356
+ if (hydro_random_init() != 0) {
357
+ abort();
358
+ }
359
+ gimli_core_u8(hydro_random_context.state, 0);
360
+ hydro_random_ratchet();
361
+ hydro_random_context.initialized = 1;
362
+ }
363
+ }
364
+
365
+ void
366
+ hydro_random_ratchet(void)
367
+ {
368
+ mem_zero(hydro_random_context.state, gimli_RATE);
369
+ STORE64_LE(hydro_random_context.state, hydro_random_context.counter);
370
+ hydro_random_context.counter++;
371
+ gimli_core_u8(hydro_random_context.state, 0);
372
+ hydro_random_context.available = gimli_RATE;
373
+ }
374
+
375
+ uint32_t
376
+ hydro_random_u32(void)
377
+ {
378
+ uint32_t v;
379
+
380
+ hydro_random_check_initialized();
381
+ if (hydro_random_context.available < 4) {
382
+ hydro_random_ratchet();
383
+ }
384
+ memcpy(&v, &hydro_random_context.state[gimli_RATE - hydro_random_context.available], 4);
385
+ hydro_random_context.available -= 4;
386
+
387
+ return v;
388
+ }
389
+
390
+ uint32_t
391
+ hydro_random_uniform(const uint32_t upper_bound)
392
+ {
393
+ uint32_t min;
394
+ uint32_t r;
395
+
396
+ if (upper_bound < 2U) {
397
+ return 0;
398
+ }
399
+ min = (1U + ~upper_bound) % upper_bound; /* = 2**32 mod upper_bound */
400
+ do {
401
+ r = hydro_random_u32();
402
+ } while (r < min);
403
+ /* r is now clamped to a set whose size mod upper_bound == 0
404
+ * the worst case (2**31+1) requires 2 attempts on average */
405
+
406
+ return r % upper_bound;
407
+ }
408
+
409
+ void
410
+ hydro_random_buf(void *out, size_t out_len)
411
+ {
412
+ uint8_t *p = (uint8_t *) out;
413
+ size_t i;
414
+ size_t leftover;
415
+
416
+ hydro_random_check_initialized();
417
+ for (i = 0; i < out_len / gimli_RATE; i++) {
418
+ gimli_core_u8(hydro_random_context.state, 0);
419
+ memcpy(p + i * gimli_RATE, hydro_random_context.state, gimli_RATE);
420
+ }
421
+ leftover = out_len % gimli_RATE;
422
+ if (leftover != 0) {
423
+ gimli_core_u8(hydro_random_context.state, 0);
424
+ mem_cpy(p + i * gimli_RATE, hydro_random_context.state, leftover);
425
+ }
426
+ hydro_random_ratchet();
427
+ }
428
+
429
+ void
430
+ hydro_random_buf_deterministic(void *out, size_t out_len,
431
+ const uint8_t seed[hydro_random_SEEDBYTES])
432
+ {
433
+ static const uint8_t prefix[] = { 7, 'd', 'r', 'b', 'g', '2', '5', '6' };
434
+ _hydro_attr_aligned_(16) uint8_t state[gimli_BLOCKBYTES];
435
+ uint8_t * p = (uint8_t *) out;
436
+ size_t i;
437
+ size_t leftover;
438
+
439
+ mem_zero(state, gimli_BLOCKBYTES);
440
+ COMPILER_ASSERT(sizeof prefix + 8 <= gimli_RATE);
441
+ memcpy(state, prefix, sizeof prefix);
442
+ STORE64_LE(state + sizeof prefix, (uint64_t) out_len);
443
+ gimli_core_u8(state, 1);
444
+ COMPILER_ASSERT(hydro_random_SEEDBYTES == gimli_RATE * 2);
445
+ mem_xor(state, seed, gimli_RATE);
446
+ gimli_core_u8(state, 2);
447
+ mem_xor(state, seed + gimli_RATE, gimli_RATE);
448
+ gimli_core_u8(state, 2);
449
+ for (i = 0; i < out_len / gimli_RATE; i++) {
450
+ gimli_core_u8(state, 0);
451
+ memcpy(p + i * gimli_RATE, state, gimli_RATE);
452
+ }
453
+ leftover = out_len % gimli_RATE;
454
+ if (leftover != 0) {
455
+ gimli_core_u8(state, 0);
456
+ mem_cpy(p + i * gimli_RATE, state, leftover);
457
+ }
458
+ }
459
+
460
+ void
461
+ hydro_random_reseed(void)
462
+ {
463
+ hydro_random_context.initialized = 0;
464
+ hydro_random_check_initialized();
465
+ }