1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
It is considered beerware. Prost. Skol. Cheers or whatever.
$id$ */
/* System */
#include <stdint.h>
#include <string.h>
/* Opentracker */
#include "ot_random.h"
#include "test.h"
/* Nothing here can test that the bytes are unpredictable, which is a property
of the generator the build selected. What these cases do pin is that the
wrapper hands the whole buffer to it, writes nothing beyond the length it
was given, and is actually wired to something that varies. The first of
those matters: the fallback this module replaced filled only the first
sixteen bytes of the sixty-four byte key buffer in ot_udp.c. */
#define DRAWS 32
#define BUFLEN 64
static void case_every_byte_varies(void) {
unsigned char first[BUFLEN], draw[BUFLEN];
unsigned char varied[BUFLEN];
size_t i, n;
test_case("every byte of the buffer comes from the generator");
memset(varied, 0, sizeof(varied));
random_bytes(first, sizeof(first));
for (n = 0; n < DRAWS; ++n) {
random_bytes(draw, sizeof(draw));
for (i = 0; i < BUFLEN; ++i)
if (draw[i] != first[i])
varied[i] = 1;
}
/* A byte position that never moved across 32 draws is not being written.
A false alarm needs all 32 draws to agree by chance, around 256^-31. */
for (i = 0; i < BUFLEN; ++i)
if (!varied[i]) {
test_failf(__FILE__, __LINE__, "byte %zu never changed over %d draws", i, DRAWS);
return;
}
++test_checks;
}
static void case_respects_length(void) {
unsigned char buf[32];
size_t i;
test_case("nothing is written past the requested length");
memset(buf, 0xA5, sizeof(buf));
random_bytes(buf, 8);
for (i = 8; i < sizeof(buf); ++i)
if (buf[i] != 0xA5) {
test_failf(__FILE__, __LINE__, "byte %zu past the end was overwritten", i);
return;
}
++test_checks;
}
static void case_zero_length(void) {
unsigned char buf[4];
test_case("a zero length request writes nothing");
memset(buf, 0x5A, sizeof(buf));
random_bytes(buf, 0);
CHECK_MEM(buf, "\x5a\x5a\x5a\x5a", 4);
}
static void case_successive_draws_differ(void) {
unsigned char a[32], b[32];
test_case("two draws differ");
random_bytes(a, sizeof(a));
random_bytes(b, sizeof(b));
CHECK(memcmp(a, b, sizeof(a)) != 0);
}
static void case_uint32_varies(void) {
uint32_t first = random_uint32();
int differs = 0;
size_t n;
test_case("random_uint32 does not return a constant");
for (n = 0; n < DRAWS; ++n)
if (random_uint32() != first)
differs = 1;
CHECK(differs);
}
static void case_uint32_uses_the_top_bit(void) {
uint32_t seen = 0;
size_t n;
test_case("random_uint32 spans the full 32 bits");
/* random() never sets bit 31, so a build that returned it unmixed would
fail this. Over 64 draws the chance of a false alarm is 2^-64. */
for (n = 0; n < 64; ++n)
seen |= random_uint32();
CHECK_INT(seen & 0x80000000u, 0x80000000u);
}
void test_random(void) {
case_every_byte_varies();
case_respects_length();
case_zero_length();
case_successive_draws_differ();
case_uint32_varies();
case_uint32_uses_the_top_bit();
}
|