Merge remote-tracking branch 'tor-gitlab/mr/513' into main
[tor.git] / src / test / test_crypto_rng.c
blob3ae97bd499cba46545c7e94f61ccaf323e1e983a
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #include "orconfig.h"
7 #define CRYPTO_RAND_PRIVATE
8 #include "core/or/or.h"
9 #include "test/test.h"
10 #include "lib/crypt_ops/aes.h"
11 #include "lib/crypt_ops/crypto_format.h"
12 #include "lib/crypt_ops/crypto_rand.h"
14 /** Run unit tests for our random number generation function and its wrappers.
16 static void
17 test_crypto_rng(void *arg)
19 int i, j, allok;
20 char data1[100], data2[100];
21 double d;
22 char *h=NULL;
24 /* Try out RNG. */
25 (void)arg;
26 tt_assert(! crypto_seed_rng());
27 crypto_rand(data1, 100);
28 crypto_rand(data2, 100);
29 tt_mem_op(data1,OP_NE, data2,100);
30 allok = 1;
31 for (i = 0; i < 100; ++i) {
32 uint64_t big;
33 char *host;
34 j = crypto_rand_int(100);
35 if (j < 0 || j >= 100)
36 allok = 0;
37 big = crypto_rand_uint64(UINT64_C(1)<<40);
38 if (big >= (UINT64_C(1)<<40))
39 allok = 0;
40 big = crypto_rand_uint64(UINT64_C(5));
41 if (big >= 5)
42 allok = 0;
43 d = crypto_rand_double();
44 tt_assert(d >= 0);
45 tt_assert(d < 1.0);
46 host = crypto_random_hostname(3,8,"www.",".onion");
47 if (strcmpstart(host,"www.") ||
48 strcmpend(host,".onion") ||
49 strlen(host) < 13 ||
50 strlen(host) > 18)
51 allok = 0;
52 tor_free(host);
55 /* Make sure crypto_random_hostname clips its inputs properly. */
56 h = crypto_random_hostname(20000, 9000, "www.", ".onion");
57 tt_assert(! strcmpstart(h,"www."));
58 tt_assert(! strcmpend(h,".onion"));
59 tt_int_op(63+4+6, OP_EQ, strlen(h));
61 tt_assert(allok);
62 done:
63 tor_free(h);
66 static void
67 test_crypto_rng_range(void *arg)
69 int got_smallest = 0, got_largest = 0;
70 int i;
72 (void)arg;
73 for (i = 0; i < 1000; ++i) {
74 int x = crypto_rand_int_range(5,9);
75 tt_int_op(x, OP_GE, 5);
76 tt_int_op(x, OP_LT, 9);
77 if (x == 5)
78 got_smallest = 1;
79 if (x == 8)
80 got_largest = 1;
82 /* These fail with probability 1/10^603. */
83 tt_assert(got_smallest);
84 tt_assert(got_largest);
86 got_smallest = got_largest = 0;
87 const uint64_t ten_billion = 10 * ((uint64_t)1000000000000);
88 for (i = 0; i < 1000; ++i) {
89 uint64_t x = crypto_rand_uint64_range(ten_billion, ten_billion+10);
90 tt_u64_op(x, OP_GE, ten_billion);
91 tt_u64_op(x, OP_LT, ten_billion+10);
92 if (x == ten_billion)
93 got_smallest = 1;
94 if (x == ten_billion+9)
95 got_largest = 1;
98 tt_assert(got_smallest);
99 tt_assert(got_largest);
101 const time_t now = time(NULL);
102 for (i = 0; i < 2000; ++i) {
103 time_t x = crypto_rand_time_range(now, now+60);
104 tt_i64_op(x, OP_GE, now);
105 tt_i64_op(x, OP_LT, now+60);
106 if (x == now)
107 got_smallest = 1;
108 if (x == now+59)
109 got_largest = 1;
112 tt_assert(got_smallest);
113 tt_assert(got_largest);
114 done:
118 static void
119 test_crypto_rng_strongest(void *arg)
121 const char *how = arg;
122 int broken = 0;
124 if (how == NULL) {
126 } else if (!strcmp(how, "nosyscall")) {
127 break_strongest_rng_syscall = 1;
128 } else if (!strcmp(how, "nofallback")) {
129 break_strongest_rng_fallback = 1;
130 } else if (!strcmp(how, "broken")) {
131 broken = break_strongest_rng_syscall = break_strongest_rng_fallback = 1;
134 #define N 128
135 uint8_t combine_and[N];
136 uint8_t combine_or[N];
137 int i, j;
139 memset(combine_and, 0xff, N);
140 memset(combine_or, 0, N);
142 for (i = 0; i < 100; ++i) { /* 2^-100 chances just don't happen. */
143 uint8_t output[N];
144 memset(output, 0, N);
145 if (how == NULL) {
146 /* this one can't fail. */
147 crypto_strongest_rand(output, sizeof(output));
148 } else {
149 int r = crypto_strongest_rand_raw(output, sizeof(output));
150 if (r == -1) {
151 if (broken) {
152 goto done; /* we're fine. */
154 /* This function is allowed to break, but only if it always breaks. */
155 tt_int_op(i, OP_EQ, 0);
156 tt_skip();
157 } else {
158 tt_assert(! broken);
161 for (j = 0; j < N; ++j) {
162 combine_and[j] &= output[j];
163 combine_or[j] |= output[j];
167 for (j = 0; j < N; ++j) {
168 tt_int_op(combine_and[j], OP_EQ, 0);
169 tt_int_op(combine_or[j], OP_EQ, 0xff);
171 done:
173 #undef N
176 static void
177 test_crypto_rng_fast(void *arg)
179 (void)arg;
180 crypto_fast_rng_t *rng = crypto_fast_rng_new();
181 tt_assert(rng);
183 /* Rudimentary black-block test to make sure that our prng outputs
184 * have all bits sometimes on and all bits sometimes off. */
185 uint64_t m1 = 0, m2 = ~(uint64_t)0;
186 const int N = 128;
188 for (int i=0; i < N; ++i) {
189 uint64_t v;
190 crypto_fast_rng_getbytes(rng, (void*)&v, sizeof(v));
191 m1 |= v;
192 m2 &= v;
195 tt_u64_op(m1, OP_EQ, ~(uint64_t)0);
196 tt_u64_op(m2, OP_EQ, 0);
198 /* Check range functions. */
199 int counts[5];
200 memset(counts, 0, sizeof(counts));
201 for (int i=0; i < N; ++i) {
202 unsigned u = crypto_fast_rng_get_uint(rng, 5);
203 tt_int_op(u, OP_GE, 0);
204 tt_int_op(u, OP_LT, 5);
205 counts[u]++;
207 uint64_t u64 = crypto_fast_rng_get_uint64(rng, UINT64_C(1)<<40);
208 tt_u64_op(u64, OP_GE, 0);
209 tt_u64_op(u64, OP_LT, UINT64_C(1)<<40);
211 double d = crypto_fast_rng_get_double(rng);
212 tt_assert(d >= 0.0);
213 tt_assert(d < 1.0);
216 /* All values should have come up once. */
217 for (int i=0; i<5; ++i) {
218 tt_int_op(counts[i], OP_GT, 0);
221 /* per-thread rand_fast shouldn't crash or leak. */
222 crypto_fast_rng_t *t_rng = get_thread_fast_rng();
223 for (int i = 0; i < N; ++i) {
224 uint64_t u64 = crypto_fast_rng_get_uint64(t_rng, UINT64_C(1)<<40);
225 tt_u64_op(u64, OP_GE, 0);
226 tt_u64_op(u64, OP_LT, UINT64_C(1)<<40);
229 done:
230 crypto_fast_rng_free(rng);
233 static void
234 test_crypto_rng_fast_whitebox(void *arg)
236 (void)arg;
237 const size_t buflen = crypto_fast_rng_get_bytes_used_per_stream();
238 char *buf = tor_malloc_zero(buflen);
239 char *buf2 = tor_malloc_zero(buflen);
240 char *buf3 = NULL, *buf4 = NULL;
242 crypto_cipher_t *cipher = NULL, *cipher2 = NULL;
243 uint8_t seed[CRYPTO_FAST_RNG_SEED_LEN];
244 memset(seed, 0, sizeof(seed));
246 /* Start with a prng with zero key and zero IV. */
247 crypto_fast_rng_t *rng = crypto_fast_rng_new_from_seed(seed);
248 tt_assert(rng);
250 /* We'll use a stream cipher to keep in sync */
251 cipher = crypto_cipher_new_with_iv_and_bits(seed, seed+32, 256);
253 /* The first 48 bytes are used for the next seed -- let's make sure we have
254 * them.
256 memset(seed, 0, sizeof(seed));
257 crypto_cipher_crypt_inplace(cipher, (char*)seed, sizeof(seed));
259 /* if we get 128 bytes, they should match the bytes from the aes256-counter
260 * stream, starting at position 48.
262 crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 128);
263 memset(buf2, 0, 128);
264 crypto_cipher_crypt_inplace(cipher, buf2, 128);
265 tt_mem_op(buf, OP_EQ, buf2, 128);
267 /* Try that again, with an odd number of bytes. */
268 crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 199);
269 memset(buf2, 0, 199);
270 crypto_cipher_crypt_inplace(cipher, buf2, 199);
271 tt_mem_op(buf, OP_EQ, buf2, 199);
273 /* Make sure that refilling works as expected: skip all but the last 5 bytes
274 * of this steam. */
275 size_t skip = buflen - (199+128) - 5;
276 crypto_fast_rng_getbytes(rng, (uint8_t*)buf, skip);
277 crypto_cipher_crypt_inplace(cipher, buf2, skip);
279 /* Now get the next 128 bytes. The first 5 will come from this stream, and
280 * the next 5 will come from the stream keyed by the new value of 'seed'. */
281 crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 128);
282 memset(buf2, 0, 128);
283 crypto_cipher_crypt_inplace(cipher, buf2, 5);
284 crypto_cipher_free(cipher);
285 cipher = crypto_cipher_new_with_iv_and_bits(seed, seed+32, 256);
286 memset(seed, 0, sizeof(seed));
287 crypto_cipher_crypt_inplace(cipher, (char*)seed, sizeof(seed));
288 crypto_cipher_crypt_inplace(cipher, buf2+5, 128-5);
289 tt_mem_op(buf, OP_EQ, buf2, 128);
291 /* And check the next 7 bytes to make sure we didn't discard anything. */
292 crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 7);
293 memset(buf2, 0, 7);
294 crypto_cipher_crypt_inplace(cipher, buf2, 7);
295 tt_mem_op(buf, OP_EQ, buf2, 7);
297 /* Now try the optimization for long outputs. */
298 buf3 = tor_malloc(65536);
299 crypto_fast_rng_getbytes(rng, (uint8_t*)buf3, 65536);
301 buf4 = tor_malloc_zero(65536);
302 uint8_t seed2[CRYPTO_FAST_RNG_SEED_LEN];
303 memset(seed2, 0, sizeof(seed2));
304 crypto_cipher_crypt_inplace(cipher, (char*)seed2, sizeof(seed2));
305 cipher2 = crypto_cipher_new_with_iv_and_bits(seed2, seed2+32, 256);
306 crypto_cipher_crypt_inplace(cipher2, buf4, 65536);
307 tt_mem_op(buf3, OP_EQ, buf4, 65536);
309 done:
310 crypto_fast_rng_free(rng);
311 crypto_cipher_free(cipher);
312 crypto_cipher_free(cipher2);
313 tor_free(buf);
314 tor_free(buf2);
315 tor_free(buf3);
316 tor_free(buf4);
319 struct testcase_t crypto_rng_tests[] = {
320 { "rng", test_crypto_rng, 0, NULL, NULL },
321 { "rng_range", test_crypto_rng_range, 0, NULL, NULL },
322 { "rng_strongest", test_crypto_rng_strongest, TT_FORK, NULL, NULL },
323 { "rng_strongest_nosyscall", test_crypto_rng_strongest, TT_FORK,
324 &passthrough_setup, (void*)"nosyscall" },
325 { "rng_strongest_nofallback", test_crypto_rng_strongest, TT_FORK,
326 &passthrough_setup, (void*)"nofallback" },
327 { "rng_strongest_broken", test_crypto_rng_strongest, TT_FORK,
328 &passthrough_setup, (void*)"broken" },
329 { "fast", test_crypto_rng_fast, 0, NULL, NULL },
330 { "fast_whitebox", test_crypto_rng_fast_whitebox, 0, NULL, NULL },
331 END_OF_TESTCASES