dualcone 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +116 -0
- data/ext/dualcone/dualcone.c +288 -0
- data/ext/dualcone/dualcone.h +49 -0
- data/ext/dualcone/extconf.rb +36 -0
- data/lib/dualcone.rb +4 -0
- data/lib/dualcone/version.rb +5 -0
- data/vendor/libhydrogen/LICENSE +18 -0
- data/vendor/libhydrogen/Makefile +61 -0
- data/vendor/libhydrogen/README.md +36 -0
- data/vendor/libhydrogen/hydrogen.c +18 -0
- data/vendor/libhydrogen/hydrogen.h +331 -0
- data/vendor/libhydrogen/impl/common.h +321 -0
- data/vendor/libhydrogen/impl/core.h +223 -0
- data/vendor/libhydrogen/impl/gimli-core.h +25 -0
- data/vendor/libhydrogen/impl/gimli-core/portable.h +39 -0
- data/vendor/libhydrogen/impl/gimli-core/sse2.h +100 -0
- data/vendor/libhydrogen/impl/hash.h +140 -0
- data/vendor/libhydrogen/impl/hydrogen_p.h +83 -0
- data/vendor/libhydrogen/impl/kdf.h +20 -0
- data/vendor/libhydrogen/impl/kx.h +535 -0
- data/vendor/libhydrogen/impl/pwhash.h +281 -0
- data/vendor/libhydrogen/impl/random.h +465 -0
- data/vendor/libhydrogen/impl/secretbox.h +236 -0
- data/vendor/libhydrogen/impl/sign.h +207 -0
- data/vendor/libhydrogen/impl/x25519.h +384 -0
- metadata +186 -0
@@ -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 = ¶ms[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 = ¶ms[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
|
+
}
|