Line data Source code
1 : #include "passgen/random.h"
2 : #include "passgen/assert.h"
3 : #include "passgen/config.h"
4 : #include "passgen/util/endian.h"
5 : #include <stdlib.h>
6 : #include <string.h>
7 :
8 29 : static bool _strprefix(const char *prefix, const char *string) {
9 29 : size_t prefix_len = strlen(prefix);
10 108 : for(size_t i = 0; i < prefix_len; i++) {
11 97 : if(prefix[i] != string[i]) {
12 18 : return false;
13 : }
14 : }
15 11 : return true;
16 : }
17 :
18 57076 : void passgen_random_reload(passgen_random *random) {
19 57076 : passgen_assert(random != NULL);
20 :
21 : // read random data.
22 : size_t bytes =
23 57076 : random->read(random->context, &random->buffer, sizeof(random->buffer));
24 : (void) bytes;
25 :
26 : // make sure we've read enough.
27 57076 : passgen_assert(bytes == sizeof(random->buffer));
28 :
29 : // reset position in ring buffer.
30 57076 : random->pos = 0;
31 57076 : }
32 :
33 11386978 : void passgen_random_read(passgen_random *random, void *data, size_t bytes) {
34 11386978 : if(bytes <= sizeof(random->buffer)) {
35 : // maximum bytes we can have right now
36 11386977 : size_t left = sizeof(random->buffer) - random->pos;
37 :
38 11386977 : if(bytes < left) {
39 : // if we have enough, just copy it over.
40 11329986 : memcpy(data, &random->buffer[random->pos], bytes);
41 11329986 : random->pos += bytes;
42 : } else {
43 : // if we don't have enough, copy over whatever we have and
44 : // reload.
45 56991 : memcpy(data, random->buffer, left);
46 56991 : passgen_random_reload(random);
47 :
48 : // if there's more to be read, recurse.
49 56991 : if(bytes != left) {
50 3 : passgen_random_read(random, data + left, bytes - left);
51 : }
52 : }
53 : } else {
54 1 : size_t ret = random->read(random->context, data, bytes);
55 1 : if(ret != bytes) {
56 0 : fprintf(
57 : stderr,
58 : "Error reading from randomness source: trying to read %zu "
59 : "bytes but got %zu",
60 : bytes,
61 : ret);
62 0 : abort();
63 : }
64 : }
65 11386978 : }
66 :
67 : passgen_random *
68 17 : passgen_random_open_parse(passgen_random *random, const char *desc) {
69 17 : if(strcmp("zero", desc) == 0) {
70 2 : return passgen_random_zero_open(random);
71 : }
72 :
73 : // check if we should read randomness from this file
74 15 : if(_strprefix("file:", desc)) {
75 5 : return passgen_random_path_open(random, &desc[5]);
76 : }
77 :
78 : // check if we should use the xorshift PRNG with the given seed
79 10 : if(_strprefix("xorshift:", desc)) {
80 6 : const char *seed_str = &desc[9];
81 6 : if(*seed_str == 0) {
82 2 : return NULL;
83 : }
84 :
85 4 : uint64_t seed = atoll(seed_str);
86 4 : if(seed == 0) {
87 2 : return NULL;
88 : }
89 :
90 2 : return passgen_random_xorshift_open(random, seed);
91 : }
92 :
93 : // check if we should use the system default
94 4 : if(0 == strcmp(desc, "system")) {
95 2 : return passgen_random_system_open(random);
96 : }
97 :
98 : #ifdef PASSGEN_MONOCYPHER
99 : // use chacha20 with raw key and IV
100 2 : if(_strprefix("chacha20:", desc)) {
101 0 : const char *key_ptr = &desc[9];
102 0 : const char *key_end = strchr(key_ptr, ':');
103 0 : if(!key_end) {
104 0 : key_end = key_ptr + strlen(key_ptr);
105 : }
106 0 : char key[32] = {0};
107 0 : memcpy(key, key_ptr, key_end - key_ptr);
108 :
109 0 : char iv[] = "passgen";
110 :
111 0 : if(*key_end == ':') {
112 0 : const char *iv_ptr = key_end + 1;
113 0 : size_t iv_len = strlen(iv_ptr);
114 0 : iv_len = iv_len > 8 ? 8 : iv_len;
115 0 : memset(iv, 0, 8);
116 0 : memcpy(iv, iv_ptr, iv_len);
117 : }
118 :
119 0 : return passgen_random_chacha20_open(random, key, iv);
120 : }
121 :
122 : // use chacha20 with raw key and IV
123 2 : if(_strprefix("chacha20-argon2:", desc)) {
124 0 : char master_pass[128] = {0};
125 0 : char domain[128] = {0};
126 0 : char token[128] = {0};
127 :
128 0 : const char *start = &desc[16];
129 0 : const char *end = &desc[16];
130 :
131 : #define PARSE_STRING(name) \
132 : if(*end == ':') end++; \
133 : if(*end) { \
134 : start = end; \
135 : end = strchr(start, ':'); \
136 : if(!end) { \
137 : end = start + strlen(start); \
138 : } \
139 : memcpy(name, start, end - start); \
140 : }
141 :
142 0 : PARSE_STRING(master_pass)
143 0 : PARSE_STRING(domain)
144 0 : PARSE_STRING(token)
145 :
146 0 : return passgen_random_chacha20_argon2_open(random, master_pass, domain, token, NULL);
147 : }
148 : #endif
149 :
150 2 : return NULL;
151 : }
152 :
153 68 : passgen_random *passgen_random_open(passgen_random *random, const char *desc) {
154 68 : if(desc) {
155 17 : return passgen_random_open_parse(random, desc);
156 : }
157 :
158 51 : return passgen_random_system_open(random);
159 : }
160 :
161 47 : void passgen_random_close(passgen_random *random) {
162 : // close randomness source
163 47 : random->close(random->context);
164 :
165 : // reset members to prevent accidental use-after-free
166 47 : PASSGEN_CLEAR(random);
167 47 : }
168 :
169 12 : void passgen_random_free(passgen_random *random) {
170 12 : passgen_random_close(random);
171 12 : free(random);
172 12 : }
173 :
174 653171 : inline uint8_t passgen_random_u8(passgen_random *random) {
175 : uint8_t data;
176 653171 : passgen_random_read(random, &data, sizeof(data));
177 653171 : return data;
178 : }
179 :
180 2332611 : inline uint16_t passgen_random_u16(passgen_random *random) {
181 : uint16_t data;
182 2332611 : passgen_random_read(random, &data, sizeof(data));
183 2332611 : data = htole16(data);
184 2332611 : return data;
185 : }
186 :
187 3536149 : inline uint32_t passgen_random_u32(passgen_random *random) {
188 : uint32_t data;
189 3536149 : passgen_random_read(random, &data, sizeof(data));
190 3536149 : data = htole32(data);
191 3536149 : return data;
192 : }
193 :
194 4863000 : inline uint64_t passgen_random_u64(passgen_random *random) {
195 : uint64_t data;
196 4863000 : passgen_random_read(random, &data, sizeof(data));
197 4863000 : data = htole64(data);
198 4863000 : return data;
199 : }
200 :
201 6 : inline bool passgen_random_bool(passgen_random *random) {
202 : uint8_t data;
203 6 : passgen_random_read(random, &data, sizeof(data));
204 6 : return (data & 128) == 0;
205 : }
206 :
207 468786 : inline uint8_t passgen_random_u8_max(passgen_random *random, uint8_t max) {
208 468786 : passgen_assert(max);
209 :
210 468786 : uint8_t mask = max;
211 468786 : mask |= mask >> 4;
212 468786 : mask |= mask >> 2;
213 468786 : mask |= mask >> 1;
214 :
215 : uint8_t num;
216 : do {
217 651109 : num = passgen_random_u8(random) & mask;
218 651109 : } while(num >= max);
219 :
220 468786 : return num;
221 : }
222 :
223 1156352 : inline uint16_t passgen_random_u16_max(passgen_random *random, uint16_t max) {
224 1156352 : passgen_assert(max);
225 :
226 1156352 : uint16_t mask = max;
227 1156352 : mask |= mask >> 8;
228 1156352 : mask |= mask >> 4;
229 1156352 : mask |= mask >> 2;
230 1156352 : mask |= mask >> 1;
231 :
232 : uint16_t num;
233 :
234 : do {
235 1464365 : num = passgen_random_u16(random) & mask;
236 1464365 : } while(num >= max);
237 :
238 1156352 : return num;
239 : }
240 :
241 1390336 : inline uint32_t passgen_random_u32_max(passgen_random *random, uint32_t max) {
242 1390336 : passgen_assert(max);
243 :
244 1390336 : uint32_t mask = max;
245 1390336 : mask |= mask >> 16;
246 1390336 : mask |= mask >> 8;
247 1390336 : mask |= mask >> 4;
248 1390336 : mask |= mask >> 2;
249 1390336 : mask |= mask >> 1;
250 :
251 : uint32_t num;
252 :
253 : do {
254 1847268 : num = passgen_random_u32(random) & mask;
255 1847268 : } while(num >= max);
256 :
257 1390336 : return num;
258 : }
259 :
260 2186626 : inline uint64_t passgen_random_u64_max(passgen_random *random, uint64_t max) {
261 2186626 : passgen_assert(max);
262 :
263 2186626 : uint64_t mask = max;
264 2186626 : mask |= mask >> 32;
265 2186626 : mask |= mask >> 16;
266 2186626 : mask |= mask >> 8;
267 2186626 : mask |= mask >> 4;
268 2186626 : mask |= mask >> 2;
269 2186626 : mask |= mask >> 1;
270 :
271 : uint64_t num;
272 :
273 : do {
274 2906348 : num = passgen_random_u64(random) & mask;
275 2906348 : } while(num >= max);
276 :
277 2186626 : return num;
278 : }
|