Line data Source code
1 : #include "passgen/random.h"
2 : #include "passgen/config.h"
3 :
4 : #include <stdbool.h>
5 : #include <stdio.h>
6 : #include <stdlib.h>
7 :
8 : #include "tests.h"
9 :
10 : /// Tests that a given function covers all possible outputs (0..max, inclusive).
11 : #define TEST_COVERAGE(max, collate, function) \
12 : do { \
13 : size_t coverage_len = ((size_t) max) / (collate) + 1ULL; \
14 : uint8_t *coverage = calloc((coverage_len + 7) / 8, 1); \
15 : bool full_coverage = false; \
16 : while(!full_coverage) { \
17 : for(size_t i = 0; i < 256; i++) { \
18 : size_t pos = function / (collate); \
19 : coverage[pos / 8] |= 1 << (pos % 8); \
20 : } \
21 : full_coverage = true; \
22 : for(size_t i = 0; i <= (max / (collate)); i++) { \
23 : if(!(coverage[i / 8] & (1 << (i % 8)))) { \
24 : full_coverage = false; \
25 : break; \
26 : } \
27 : } \
28 : } \
29 : free(coverage); \
30 : } while(false)
31 :
32 2 : double standard_deviation(size_t count, uint32_t *elements) {
33 : (void) count;
34 : (void) elements;
35 : // TODO: determine deviation
36 2 : return 0;
37 : }
38 :
39 : /// Tests that a given function has an even distribution
40 : #define TEST_DISTRIBUTION(max, bucket_num, target, function) \
41 : uint32_t *buckets = calloc(bucket_num, sizeof(uint32_t)); \
42 : while(true) { \
43 : size_t bucket = function / ((max) / (bucket_num) + 1); \
44 : buckets[bucket] += 1; \
45 : if(buckets[bucket] == target) { \
46 : break; \
47 : } \
48 : } \
49 : assert(standard_deviation(bucket_num, buckets) < 10); \
50 : free(buckets)
51 :
52 1 : test_result test_random_u8(void) {
53 : passgen_random random;
54 1 : assert(passgen_random_open(&random, NULL));
55 :
56 2745 : TEST_COVERAGE(UINT8_MAX, 1, passgen_random_u8(&random));
57 :
58 1 : passgen_random_close(&random);
59 :
60 1 : return test_ok;
61 : }
62 :
63 1 : test_result test_random_u8_max(void) {
64 : passgen_random random;
65 1 : assert(passgen_random_open(&random, NULL));
66 :
67 255 : for(size_t max = 1; max < UINT8_MAX; max++) {
68 279071 : TEST_COVERAGE(max - 1, 1, passgen_random_u8_max(&random, max));
69 : }
70 :
71 1 : passgen_random_close(&random);
72 :
73 1 : return test_ok;
74 : }
75 :
76 1 : test_result test_random_u16(void) {
77 : passgen_random random;
78 1 : assert(passgen_random_open(&random, NULL));
79 :
80 18939245 : TEST_COVERAGE(UINT16_MAX, 1, passgen_random_u16(&random));
81 :
82 1 : passgen_random_close(&random);
83 :
84 1 : return test_ok;
85 : }
86 :
87 1 : test_result test_random_u16_max(void) {
88 : passgen_random random;
89 1 : assert(passgen_random_open(&random, NULL));
90 :
91 255 : for(size_t max = 1; max < UINT8_MAX; max++) {
92 266879 : TEST_COVERAGE(max - 1, 1, passgen_random_u16_max(&random, max));
93 : }
94 :
95 12 : for(size_t max = 1; max < UINT16_MAX; max *= 3) {
96 16899591 : TEST_COVERAGE(max - 1, 1, passgen_random_u16_max(&random, max));
97 : }
98 :
99 1 : passgen_random_close(&random);
100 :
101 1 : return test_ok;
102 : }
103 :
104 1 : test_result test_random_u32(void) {
105 : passgen_random random;
106 1 : assert(passgen_random_open(&random, NULL));
107 :
108 7650941 : TEST_COVERAGE(UINT32_MAX, 1 << 16, passgen_random_u32(&random));
109 943787 : TEST_DISTRIBUTION(
110 : UINT32_MAX,
111 : 1 << 10,
112 : 1 << 10,
113 : passgen_random_u32(&random));
114 :
115 1 : passgen_random_close(&random);
116 :
117 1 : return test_ok;
118 : }
119 :
120 1 : test_result test_random_u32_max(void) {
121 : passgen_random random;
122 1 : assert(passgen_random_open(&random, NULL));
123 :
124 255 : for(size_t max = 1; max < UINT8_MAX; max++) {
125 273812 : TEST_COVERAGE(max - 1, 1, passgen_random_u32_max(&random, max));
126 : }
127 :
128 12 : for(size_t max = 1; max < UINT16_MAX; max *= 3) {
129 23552414 : TEST_COVERAGE(max - 1, 1, passgen_random_u32_max(&random, max));
130 : }
131 :
132 1 : passgen_random_close(&random);
133 :
134 1 : return test_ok;
135 : }
136 :
137 1 : test_result test_random_u64(void) {
138 : passgen_random random;
139 1 : assert(passgen_random_open(&random, NULL));
140 :
141 : // FIXME
142 : //TEST_COVERAGE(UINT64_MAX, 1ULL << 48, 1024, passgen_random_u32(&random));
143 956600 : TEST_DISTRIBUTION(
144 : UINT64_MAX,
145 : 1 << 10,
146 : 1 << 10,
147 : passgen_random_u64(&random));
148 :
149 1 : passgen_random_close(&random);
150 :
151 1 : return test_ok;
152 : }
153 :
154 1 : test_result test_random_u64_max(void) {
155 : passgen_random random;
156 1 : assert(passgen_random_open(&random, NULL));
157 :
158 255 : for(size_t max = 1; max < UINT8_MAX; max++) {
159 274422 : TEST_COVERAGE(max - 1, 1, passgen_random_u64_max(&random, max));
160 : }
161 :
162 12 : for(size_t max = 1; max < UINT16_MAX; max *= 3) {
163 30170954 : TEST_COVERAGE(max - 1, 1, passgen_random_u64_max(&random, max));
164 : }
165 :
166 1000000 : for(size_t i = 1; i < 1000000; i++) {
167 999999 : uint32_t max = passgen_random_u64(&random);
168 :
169 999999 : assert(passgen_random_u64_max(&random, max) < max);
170 : }
171 :
172 1 : passgen_random_close(&random);
173 :
174 1 : return test_ok;
175 : }
176 :
177 1 : test_result test_random_new(void) {
178 1 : passgen_random *random_default = passgen_random_open(NULL, NULL);
179 1 : assert(random_default);
180 1 : assert(random_default->read);
181 1 : assert(random_default->close);
182 :
183 1 : passgen_random *random = passgen_random_open(NULL, "system");
184 1 : assert(random);
185 1 : assert_eq(random->read, random_default->read);
186 1 : assert_eq(random->close, random_default->close);
187 1 : passgen_random_free(random);
188 1 : passgen_random_free(random_default);
189 :
190 1 : random = passgen_random_open(NULL, "zero");
191 1 : assert(random);
192 1 : assert(random->read);
193 1 : assert(random->close);
194 1 : assert_eq(passgen_random_u8(random), 0);
195 1 : assert_eq(passgen_random_u16(random), 0);
196 1 : assert_eq(passgen_random_u32(random), 0);
197 1 : assert_eq(passgen_random_u64(random), 0);
198 1 : passgen_random_free(random);
199 :
200 1 : random = passgen_random_open(NULL, "xorshift:1234");
201 1 : assert(random);
202 1 : assert(random->read);
203 1 : assert(random->close);
204 1 : assert_eq(passgen_random_u8(random), 91);
205 1 : assert_eq(passgen_random_u16(random), 11632);
206 1 : assert_eq(passgen_random_u32(random), 79584);
207 1 : assert_eq(passgen_random_u64(random), 3801598356675656448ULL);
208 1 : assert_eq(passgen_random_u64_max(random, 999999999), 851051297);
209 1 : passgen_random_free(random);
210 :
211 1 : random = passgen_random_open(NULL, "file:/dev/zero");
212 1 : assert(random);
213 1 : assert(random->read);
214 1 : assert(random->close);
215 1 : assert_eq(passgen_random_u8(random), 0);
216 1 : assert_eq(passgen_random_u16(random), 0);
217 1 : assert_eq(passgen_random_u32(random), 0);
218 1 : assert_eq(passgen_random_u64(random), 0);
219 1 : passgen_random_free(random);
220 :
221 1 : assert(!passgen_random_open(NULL, "other"));
222 1 : assert(!passgen_random_open(NULL, "xorshift:abc"));
223 1 : assert(!passgen_random_open(NULL, "xorshift:"));
224 1 : assert(!passgen_random_open(NULL, "file:"));
225 1 : assert(!passgen_random_open(NULL, "file:/dev/nonexistant"));
226 :
227 1 : return test_ok;
228 : }
229 :
230 1 : test_result test_random_file(void) {
231 1 : FILE *file = fopen("/dev/zero", "r");
232 1 : assert(file);
233 1 : passgen_random *random = passgen_random_file_open(NULL, file);
234 1 : assert(random);
235 1 : assert(random->read);
236 1 : assert(random->close);
237 1 : assert_eq(passgen_random_u8(random), 0);
238 1 : assert_eq(passgen_random_u16(random), 0);
239 1 : assert_eq(passgen_random_u32(random), 0);
240 1 : assert_eq(passgen_random_u64(random), 0);
241 1 : passgen_random_free(random);
242 :
243 1 : return test_ok;
244 : }
245 :
246 1 : test_result test_random_zero(void) {
247 1 : passgen_random *random = passgen_random_zero_open(NULL);
248 1 : assert(random);
249 1 : assert(random->read);
250 1 : assert(random->close);
251 1 : assert_eq(passgen_random_u8(random), 0);
252 1 : assert_eq(passgen_random_u16(random), 0);
253 1 : assert_eq(passgen_random_u32(random), 0);
254 1 : assert_eq(passgen_random_u64(random), 0);
255 1 : passgen_random_free(random);
256 :
257 1 : return test_ok;
258 : }
259 :
260 1 : test_result test_random_new_path(void) {
261 : passgen_random *random;
262 1 : random = passgen_random_path_open(NULL, "/dev/nonexistent");
263 1 : assert(!random);
264 :
265 : // reading from /dev/zero should always yield zero.
266 1 : random = passgen_random_path_open(NULL, "/dev/zero");
267 1 : assert(random);
268 1 : assert(random->context);
269 1 : assert(passgen_random_u8(random) == 0);
270 1 : assert(passgen_random_u16(random) == 0);
271 1 : assert(passgen_random_u32(random) == 0);
272 1 : assert(passgen_random_u64(random) == 0);
273 1 : passgen_random_free(random);
274 :
275 1 : return test_ok;
276 : }
277 :
278 1 : test_result test_random_open(void) {
279 : passgen_random random;
280 1 : assert(passgen_random_open(&random, NULL));
281 1 : assert(random.read);
282 1 : assert(random.close);
283 1 : passgen_random_close(&random);
284 1 : assert(!random.read);
285 :
286 1 : assert(passgen_random_open(&random, "system"));
287 1 : assert(random.read);
288 1 : assert(random.close);
289 1 : passgen_random_close(&random);
290 :
291 1 : assert(passgen_random_open(&random, "xorshift:1234"));
292 1 : assert(random.read);
293 1 : assert(random.close);
294 1 : passgen_random_close(&random);
295 :
296 1 : assert(passgen_random_open(&random, "zero"));
297 1 : assert(random.read);
298 1 : assert(random.close);
299 1 : passgen_random_close(&random);
300 :
301 1 : assert(passgen_random_open(&random, "file:/dev/random"));
302 1 : assert(random.read);
303 1 : assert(random.close);
304 1 : passgen_random_close(&random);
305 :
306 1 : assert(!passgen_random_open(&random, "other"));
307 1 : assert(!passgen_random_open(&random, "file:/dev/notexists"));
308 1 : assert(!passgen_random_open(&random, "xorshift:"));
309 1 : assert(!passgen_random_open(&random, "xorshift:abc"));
310 :
311 1 : return test_ok;
312 : }
313 :
314 1 : test_result test_random_path_open(void) {
315 : passgen_random random;
316 1 : assert(!passgen_random_path_open(&random, "/dev/nonexistent"));
317 :
318 1 : assert(passgen_random_path_open(&random, "/dev/zero"));
319 1 : assert(random.context);
320 1 : assert(passgen_random_u8(&random) == 0);
321 1 : assert(passgen_random_u16(&random) == 0);
322 1 : assert(passgen_random_u32(&random) == 0);
323 1 : assert(passgen_random_u64(&random) == 0);
324 1 : passgen_random_close(&random);
325 1 : assert(!random.context);
326 :
327 1 : return test_ok;
328 : }
329 :
330 : #define XORSHIFT_SEED 234720984723
331 :
332 1 : test_result test_random_read(void) {
333 : passgen_random random;
334 1 : assert(passgen_random_xorshift_open(&random, XORSHIFT_SEED));
335 :
336 1 : uint8_t data[2000] = {0};
337 :
338 : // fill small.
339 1 : passgen_random_read(&random, &data[0], 1);
340 1 : assert(random.pos == 1);
341 1 : assert(data[0] == random.buffer[0]);
342 1 : assert(data[1] == 0);
343 :
344 1 : passgen_random_read(&random, &data[0], 2);
345 1 : assert(random.pos == 3);
346 1 : assert(data[0] == random.buffer[1]);
347 1 : assert(data[1] == random.buffer[2]);
348 1 : assert(data[2] == 0);
349 :
350 1 : passgen_random_read(&random, &data[0], 4);
351 1 : assert(random.pos == 7);
352 1 : assert(data[0] == random.buffer[3]);
353 1 : assert(data[1] == random.buffer[4]);
354 1 : assert(data[2] == random.buffer[5]);
355 1 : assert(data[3] == random.buffer[6]);
356 1 : assert(data[4] == 0);
357 :
358 1 : passgen_random_read(&random, &data[0], 8);
359 1 : assert(random.pos == 15);
360 1 : assert(data[0] == random.buffer[7]);
361 1 : assert(data[1] == random.buffer[8]);
362 1 : assert(data[2] == random.buffer[9]);
363 1 : assert(data[3] == random.buffer[10]);
364 1 : assert(data[4] == random.buffer[11]);
365 1 : assert(data[5] == random.buffer[12]);
366 1 : assert(data[6] == random.buffer[13]);
367 1 : assert(data[7] == random.buffer[14]);
368 1 : assert(data[8] == 0);
369 :
370 : // test wraparound.
371 1009 : while(random.pos != (sizeof(random.buffer) - 1)) {
372 1008 : passgen_random_read(&random, &data[0], 1);
373 : }
374 1 : passgen_random_read(&random, &data[0], 1);
375 1 : assert(random.pos == 0);
376 :
377 1024 : while(random.pos != (sizeof(random.buffer) - 1)) {
378 1023 : passgen_random_read(&random, &data[0], 1);
379 : }
380 1 : passgen_random_read(&random, &data[0], 3);
381 1 : assert(data[1] == random.buffer[0]);
382 1 : assert(data[2] == random.buffer[1]);
383 1 : assert(random.pos == 2);
384 :
385 : // test reading larger.
386 1 : passgen_random_read(&random, &data[0], sizeof(random.buffer) + 1);
387 1 : assert(random.pos == 2);
388 :
389 1 : passgen_random_close(&random);
390 :
391 1 : return test_ok;
392 : }
393 :
394 : #undef XORSHIFT_SEED
395 :
396 1 : test_result test_random_xorshift(void) {
397 : passgen_random random;
398 :
399 : // using a state of zero generates only zeroes.
400 1 : assert(passgen_random_xorshift_open(&random, 0) != NULL);
401 1 : assert(passgen_random_u8(&random) == 0);
402 1 : assert(passgen_random_u16(&random) == 0);
403 1 : assert(passgen_random_u32(&random) == 0);
404 1 : assert(passgen_random_u64(&random) == 0);
405 1 : passgen_random_close(&random);
406 :
407 : // same seed always yields the same output
408 1 : assert(passgen_random_xorshift_open(&random, 123) != NULL);
409 1 : assert(passgen_random_u8(&random) == 187);
410 1 : assert(passgen_random_u16(&random) == 31102);
411 1 : assert(passgen_random_u32(&random) == 7933);
412 1 : assert(passgen_random_u64(&random) == 2214108778545186304ULL);
413 1 : passgen_random_close(&random);
414 :
415 1 : return test_ok;
416 : }
417 :
418 : #define CHECK_BEGINNING(random) \
419 : assert(passgen_random_u8(random) == 180); \
420 : assert(passgen_random_u16(random) == 43073); \
421 : assert(passgen_random_u32(random) == 1604870485)
422 :
423 : #define CHECK_REST(random) \
424 : assert(passgen_random_u64(random) == 5567227278517054982ULL); \
425 : assert(passgen_random_u64(random) == 10120912194545613486ULL); \
426 : assert(passgen_random_u64(random) == 14168488844181147231ULL); \
427 : assert(passgen_random_u64(random) == 17990605897407475310ULL); \
428 : assert(passgen_random_u64(random) == 14488897527995456554ULL); \
429 : assert(passgen_random_u64(random) == 16603445463307625220ULL); \
430 : assert(passgen_random_u64(random) == 17826730983279974707ULL); \
431 : assert(passgen_random_u64(random) == 7745812445609307379ULL); \
432 : assert(passgen_random_u64(random) == 6756294678665739130ULL)
433 :
434 : #ifdef PASSGEN_MONOCYPHER
435 1 : test_result test_random_chacha20_seek(void) {
436 : passgen_random random;
437 :
438 1 : assert(
439 : passgen_random_chacha20_open(
440 : &random,
441 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
442 : "passgen") != NULL);
443 1 : CHECK_BEGINNING(&random);
444 1 : CHECK_REST(&random);
445 :
446 : // seek back to beginning, same values
447 1 : passgen_random_chacha20_seek(&random, 0);
448 1 : CHECK_BEGINNING(&random);
449 1 : CHECK_REST(&random);
450 :
451 : // seek to middle of stream, only latter values
452 1 : passgen_random_chacha20_seek(&random, 7);
453 1 : CHECK_REST(&random);
454 :
455 1 : passgen_random_close(&random);
456 :
457 1 : return test_ok;
458 : }
459 :
460 : #undef CHECK_BEGINNING
461 : #undef CHECK_REST
462 :
463 1 : test_result test_random_chacha20(void) {
464 : passgen_random random;
465 :
466 1 : assert(
467 : passgen_random_chacha20_open(
468 : &random,
469 : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
470 : "passgen") != NULL);
471 1 : assert(passgen_random_u8(&random) == 180);
472 1 : assert(passgen_random_u16(&random) == 43073);
473 1 : assert(passgen_random_u32(&random) == 1604870485);
474 1 : assert(passgen_random_u64(&random) == 5567227278517054982ULL);
475 1 : passgen_random_close(&random);
476 :
477 1 : assert(
478 : passgen_random_chacha20_open(
479 : &random,
480 : "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
481 : "passgen") != NULL);
482 1 : assert(passgen_random_u8(&random) == 14);
483 1 : assert(passgen_random_u16(&random) == 19281);
484 1 : assert(passgen_random_u32(&random) == 2608689089);
485 1 : assert(passgen_random_u64(&random) == 12744604773769097796ULL);
486 1 : passgen_random_close(&random);
487 :
488 1 : return test_ok;
489 : }
490 :
491 1 : test_result test_random_chacha20_argon2(void) {
492 : passgen_random random;
493 :
494 1 : assert(
495 : passgen_random_chacha20_argon2_open(
496 : &random,
497 : "mypassword",
498 : "google.com",
499 : "",
500 : NULL) != NULL);
501 1 : assert(passgen_random_u8(&random) == 53);
502 1 : assert(passgen_random_u16(&random) == 45909);
503 1 : assert(passgen_random_u32(&random) == 1750958599);
504 1 : assert(passgen_random_u64(&random) == 13270789079271667756ULL);
505 1 : passgen_random_close(&random);
506 :
507 1 : return test_ok;
508 : }
509 :
510 : #endif
|