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 */
7 #define CRYPTO_RAND_PRIVATE
8 #include "core/or/or.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.
17 test_crypto_rng(void *arg
)
20 char data1
[100], data2
[100];
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);
31 for (i
= 0; i
< 100; ++i
) {
34 j
= crypto_rand_int(100);
35 if (j
< 0 || j
>= 100)
37 big
= crypto_rand_uint64(UINT64_C(1)<<40);
38 if (big
>= (UINT64_C(1)<<40))
40 big
= crypto_rand_uint64(UINT64_C(5));
43 d
= crypto_rand_double();
46 host
= crypto_random_hostname(3,8,"www.",".onion");
47 if (strcmpstart(host
,"www.") ||
48 strcmpend(host
,".onion") ||
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
));
67 test_crypto_rng_range(void *arg
)
69 int got_smallest
= 0, got_largest
= 0;
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);
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);
94 if (x
== ten_billion
+9)
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);
112 tt_assert(got_smallest
);
113 tt_assert(got_largest
);
119 test_crypto_rng_strongest(void *arg
)
121 const char *how
= arg
;
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;
135 uint8_t combine_and
[N
];
136 uint8_t combine_or
[N
];
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. */
144 memset(output
, 0, N
);
146 /* this one can't fail. */
147 crypto_strongest_rand(output
, sizeof(output
));
149 int r
= crypto_strongest_rand_raw(output
, sizeof(output
));
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);
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);
177 test_crypto_rng_fast(void *arg
)
180 crypto_fast_rng_t
*rng
= crypto_fast_rng_new();
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;
188 for (int i
=0; i
< N
; ++i
) {
190 crypto_fast_rng_getbytes(rng
, (void*)&v
, sizeof(v
));
195 tt_u64_op(m1
, OP_EQ
, ~(uint64_t)0);
196 tt_u64_op(m2
, OP_EQ
, 0);
198 /* Check range functions. */
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);
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
);
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);
230 crypto_fast_rng_free(rng
);
234 test_crypto_rng_fast_whitebox(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
);
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
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
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);
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);
310 crypto_fast_rng_free(rng
);
311 crypto_cipher_free(cipher
);
312 crypto_cipher_free(cipher2
);
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
},