LCOV - code coverage report
Current view: top level - test - test_crypto_rng.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 197 202 97.5 %
Date: 2021-11-24 03:28:48 Functions: 5 5 100.0 %

          Line data    Source code
       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 */
       5             : 
       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"
      13             : 
      14             : /** Run unit tests for our random number generation function and its wrappers.
      15             :  */
      16             : static void
      17           1 : test_crypto_rng(void *arg)
      18             : {
      19           1 :   int i, j, allok;
      20           1 :   char data1[100], data2[100];
      21           1 :   double d;
      22           1 :   char *h=NULL;
      23             : 
      24             :   /* Try out RNG. */
      25           1 :   (void)arg;
      26           1 :   tt_assert(! crypto_seed_rng());
      27           1 :   crypto_rand(data1, 100);
      28           1 :   crypto_rand(data2, 100);
      29           1 :   tt_mem_op(data1,OP_NE, data2,100);
      30             :   allok = 1;
      31         101 :   for (i = 0; i < 100; ++i) {
      32         100 :     uint64_t big;
      33         100 :     char *host;
      34         100 :     j = crypto_rand_int(100);
      35         100 :     if (j < 0 || j >= 100)
      36           0 :       allok = 0;
      37         100 :     big = crypto_rand_uint64(UINT64_C(1)<<40);
      38         100 :     if (big >= (UINT64_C(1)<<40))
      39           0 :       allok = 0;
      40         100 :     big = crypto_rand_uint64(UINT64_C(5));
      41         100 :     if (big >= 5)
      42           0 :       allok = 0;
      43         100 :     d = crypto_rand_double();
      44         100 :     tt_assert(d >= 0);
      45         100 :     tt_assert(d < 1.0);
      46         100 :     host = crypto_random_hostname(3,8,"www.",".onion");
      47         200 :     if (strcmpstart(host,"www.") ||
      48         100 :         strcmpend(host,".onion") ||
      49         100 :         strlen(host) < 13 ||
      50             :         strlen(host) > 18)
      51             :       allok = 0;
      52         100 :     tor_free(host);
      53             :   }
      54             : 
      55             :   /* Make sure crypto_random_hostname clips its inputs properly. */
      56           1 :   h = crypto_random_hostname(20000, 9000, "www.", ".onion");
      57           1 :   tt_assert(! strcmpstart(h,"www."));
      58           1 :   tt_assert(! strcmpend(h,".onion"));
      59           1 :   tt_int_op(63+4+6, OP_EQ, strlen(h));
      60             : 
      61           1 :   tt_assert(allok);
      62           1 :  done:
      63           1 :   tor_free(h);
      64           1 : }
      65             : 
      66             : static void
      67           1 : test_crypto_rng_range(void *arg)
      68             : {
      69           1 :   int got_smallest = 0, got_largest = 0;
      70           1 :   int i;
      71             : 
      72           1 :   (void)arg;
      73        1001 :   for (i = 0; i < 1000; ++i) {
      74        1000 :     int x = crypto_rand_int_range(5,9);
      75        1000 :     tt_int_op(x, OP_GE, 5);
      76        1000 :     tt_int_op(x, OP_LT, 9);
      77        1000 :     if (x == 5)
      78         253 :       got_smallest = 1;
      79        1000 :     if (x == 8)
      80         248 :       got_largest = 1;
      81             :   }
      82             :   /* These fail with probability 1/10^603. */
      83           1 :   tt_assert(got_smallest);
      84           1 :   tt_assert(got_largest);
      85             : 
      86             :   got_smallest = got_largest = 0;
      87             :   const uint64_t ten_billion = 10 * ((uint64_t)1000000000000);
      88        1001 :   for (i = 0; i < 1000; ++i) {
      89        1000 :     uint64_t x = crypto_rand_uint64_range(ten_billion, ten_billion+10);
      90        1000 :     tt_u64_op(x, OP_GE, ten_billion);
      91        1000 :     tt_u64_op(x, OP_LT, ten_billion+10);
      92        1000 :     if (x == ten_billion)
      93         100 :       got_smallest = 1;
      94        1000 :     if (x == ten_billion+9)
      95          92 :       got_largest = 1;
      96             :   }
      97             : 
      98           1 :   tt_assert(got_smallest);
      99           1 :   tt_assert(got_largest);
     100             : 
     101           1 :   const time_t now = time(NULL);
     102        2002 :   for (i = 0; i < 2000; ++i) {
     103        2000 :     time_t x = crypto_rand_time_range(now, now+60);
     104        2000 :     tt_i64_op(x, OP_GE, now);
     105        2000 :     tt_i64_op(x, OP_LT, now+60);
     106        2000 :     if (x == now)
     107          32 :       got_smallest = 1;
     108        2000 :     if (x == now+59)
     109          36 :       got_largest = 1;
     110             :   }
     111             : 
     112           1 :   tt_assert(got_smallest);
     113           1 :   tt_assert(got_largest);
     114           1 :  done:
     115           1 :   ;
     116           1 : }
     117             : 
     118             : static void
     119           4 : test_crypto_rng_strongest(void *arg)
     120             : {
     121           4 :   const char *how = arg;
     122           4 :   int broken = 0;
     123             : 
     124           4 :   if (how == NULL) {
     125             :     ;
     126           3 :   } else if (!strcmp(how, "nosyscall")) {
     127           1 :     break_strongest_rng_syscall = 1;
     128           2 :   } else if (!strcmp(how, "nofallback")) {
     129           1 :     break_strongest_rng_fallback = 1;
     130           1 :   } else if (!strcmp(how, "broken")) {
     131           1 :     broken = break_strongest_rng_syscall = break_strongest_rng_fallback = 1;
     132             :   }
     133             : 
     134             : #define N 128
     135           4 :   uint8_t combine_and[N];
     136           4 :   uint8_t combine_or[N];
     137           4 :   int i, j;
     138             : 
     139           4 :   memset(combine_and, 0xff, N);
     140           4 :   memset(combine_or, 0, N);
     141             : 
     142         304 :   for (i = 0; i < 100; ++i) { /* 2^-100 chances just don't happen. */
     143         301 :     uint8_t output[N];
     144         301 :     memset(output, 0, N);
     145         301 :     if (how == NULL) {
     146             :       /* this one can't fail. */
     147         100 :       crypto_strongest_rand(output, sizeof(output));
     148             :     } else {
     149         201 :       int r = crypto_strongest_rand_raw(output, sizeof(output));
     150         201 :       if (r == -1) {
     151           1 :         if (broken) {
     152           1 :           goto done; /* we're fine. */
     153             :         }
     154             :         /* This function is allowed to break, but only if it always breaks. */
     155           0 :         tt_int_op(i, OP_EQ, 0);
     156           0 :         tt_skip();
     157             :       } else {
     158         200 :         tt_assert(! broken);
     159             :       }
     160             :     }
     161       38700 :     for (j = 0; j < N; ++j) {
     162       38400 :       combine_and[j] &= output[j];
     163       38400 :       combine_or[j] |= output[j];
     164             :     }
     165             :   }
     166             : 
     167         387 :   for (j = 0; j < N; ++j) {
     168         384 :     tt_int_op(combine_and[j], OP_EQ, 0);
     169         384 :     tt_int_op(combine_or[j], OP_EQ, 0xff);
     170             :   }
     171           3 :  done:
     172           4 :   ;
     173             : #undef N
     174           4 : }
     175             : 
     176             : static void
     177           1 : test_crypto_rng_fast(void *arg)
     178             : {
     179           1 :   (void)arg;
     180           1 :   crypto_fast_rng_t *rng = crypto_fast_rng_new();
     181           1 :   tt_assert(rng);
     182             : 
     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;
     187             : 
     188         129 :   for (int i=0; i < N; ++i) {
     189         128 :     uint64_t v;
     190         128 :     crypto_fast_rng_getbytes(rng, (void*)&v, sizeof(v));
     191         128 :     m1 |= v;
     192         128 :     m2 &= v;
     193             :   }
     194             : 
     195           1 :   tt_u64_op(m1, OP_EQ, ~(uint64_t)0);
     196           1 :   tt_u64_op(m2, OP_EQ, 0);
     197             : 
     198             :   /* Check range functions. */
     199           1 :   int counts[5];
     200           1 :   memset(counts, 0, sizeof(counts));
     201         129 :   for (int i=0; i < N; ++i) {
     202         128 :     unsigned u = crypto_fast_rng_get_uint(rng, 5);
     203         128 :     tt_int_op(u, OP_GE, 0);
     204         128 :     tt_int_op(u, OP_LT, 5);
     205         128 :     counts[u]++;
     206             : 
     207         128 :     uint64_t u64 = crypto_fast_rng_get_uint64(rng, UINT64_C(1)<<40);
     208         128 :     tt_u64_op(u64, OP_GE, 0);
     209         128 :     tt_u64_op(u64, OP_LT, UINT64_C(1)<<40);
     210             : 
     211         128 :     double d = crypto_fast_rng_get_double(rng);
     212         128 :     tt_assert(d >= 0.0);
     213         128 :     tt_assert(d < 1.0);
     214             :   }
     215             : 
     216             :   /* All values should have come up once. */
     217           6 :   for (int i=0; i<5; ++i) {
     218           5 :     tt_int_op(counts[i], OP_GT, 0);
     219             :   }
     220             : 
     221             :   /* per-thread rand_fast shouldn't crash or leak. */
     222           1 :   crypto_fast_rng_t *t_rng = get_thread_fast_rng();
     223         129 :   for (int i = 0; i < N; ++i) {
     224         128 :     uint64_t u64 = crypto_fast_rng_get_uint64(t_rng, UINT64_C(1)<<40);
     225         128 :     tt_u64_op(u64, OP_GE, 0);
     226         128 :     tt_u64_op(u64, OP_LT, UINT64_C(1)<<40);
     227             :   }
     228             : 
     229           1 :  done:
     230           1 :   crypto_fast_rng_free(rng);
     231           1 : }
     232             : 
     233             : static void
     234           1 : test_crypto_rng_fast_whitebox(void *arg)
     235             : {
     236           1 :   (void)arg;
     237           1 :   const size_t buflen = crypto_fast_rng_get_bytes_used_per_stream();
     238           1 :   char *buf = tor_malloc_zero(buflen);
     239           1 :   char *buf2 = tor_malloc_zero(buflen);
     240           1 :   char *buf3 = NULL, *buf4 = NULL;
     241             : 
     242           1 :   crypto_cipher_t *cipher = NULL, *cipher2 = NULL;
     243           1 :   uint8_t seed[CRYPTO_FAST_RNG_SEED_LEN];
     244           1 :   memset(seed, 0, sizeof(seed));
     245             : 
     246             :   /* Start with a prng with zero key and zero IV. */
     247           1 :   crypto_fast_rng_t *rng = crypto_fast_rng_new_from_seed(seed);
     248           1 :   tt_assert(rng);
     249             : 
     250             :   /* We'll use a stream cipher to keep in sync */
     251           1 :   cipher = crypto_cipher_new_with_iv_and_bits(seed, seed+32, 256);
     252             : 
     253             :   /* The first 48 bytes are used for the next seed -- let's make sure we have
     254             :    * them.
     255             :    */
     256           1 :   memset(seed, 0, sizeof(seed));
     257           1 :   crypto_cipher_crypt_inplace(cipher, (char*)seed, sizeof(seed));
     258             : 
     259             :   /* if we get 128 bytes, they should match the bytes from the aes256-counter
     260             :    * stream, starting at position 48.
     261             :    */
     262           1 :   crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 128);
     263           1 :   memset(buf2, 0, 128);
     264           1 :   crypto_cipher_crypt_inplace(cipher, buf2, 128);
     265           1 :   tt_mem_op(buf, OP_EQ, buf2, 128);
     266             : 
     267             :   /* Try that again, with an odd number of bytes. */
     268           1 :   crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 199);
     269           1 :   memset(buf2, 0, 199);
     270           1 :   crypto_cipher_crypt_inplace(cipher, buf2, 199);
     271           1 :   tt_mem_op(buf, OP_EQ, buf2, 199);
     272             : 
     273             :   /* Make sure that refilling works as expected: skip all but the last 5 bytes
     274             :    * of this steam. */
     275           1 :   size_t skip = buflen - (199+128) - 5;
     276           1 :   crypto_fast_rng_getbytes(rng, (uint8_t*)buf, skip);
     277           1 :   crypto_cipher_crypt_inplace(cipher, buf2, skip);
     278             : 
     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           1 :   crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 128);
     282           1 :   memset(buf2, 0, 128);
     283           1 :   crypto_cipher_crypt_inplace(cipher, buf2, 5);
     284           1 :   crypto_cipher_free(cipher);
     285           1 :   cipher = crypto_cipher_new_with_iv_and_bits(seed, seed+32, 256);
     286           1 :   memset(seed, 0, sizeof(seed));
     287           1 :   crypto_cipher_crypt_inplace(cipher, (char*)seed, sizeof(seed));
     288           1 :   crypto_cipher_crypt_inplace(cipher, buf2+5, 128-5);
     289           1 :   tt_mem_op(buf, OP_EQ, buf2, 128);
     290             : 
     291             :   /* And check the next 7 bytes to make sure we didn't discard anything. */
     292           1 :   crypto_fast_rng_getbytes(rng, (uint8_t*)buf, 7);
     293           1 :   memset(buf2, 0, 7);
     294           1 :   crypto_cipher_crypt_inplace(cipher, buf2, 7);
     295           1 :   tt_mem_op(buf, OP_EQ, buf2, 7);
     296             : 
     297             :   /* Now try the optimization for long outputs. */
     298           1 :   buf3 = tor_malloc(65536);
     299           1 :   crypto_fast_rng_getbytes(rng, (uint8_t*)buf3, 65536);
     300             : 
     301           1 :   buf4 = tor_malloc_zero(65536);
     302           1 :   uint8_t seed2[CRYPTO_FAST_RNG_SEED_LEN];
     303           1 :   memset(seed2, 0, sizeof(seed2));
     304           1 :   crypto_cipher_crypt_inplace(cipher, (char*)seed2, sizeof(seed2));
     305           1 :   cipher2 = crypto_cipher_new_with_iv_and_bits(seed2, seed2+32, 256);
     306           1 :   crypto_cipher_crypt_inplace(cipher2, buf4, 65536);
     307           1 :   tt_mem_op(buf3, OP_EQ, buf4, 65536);
     308             : 
     309           1 :  done:
     310           1 :   crypto_fast_rng_free(rng);
     311           1 :   crypto_cipher_free(cipher);
     312           1 :   crypto_cipher_free(cipher2);
     313           1 :   tor_free(buf);
     314           1 :   tor_free(buf2);
     315           1 :   tor_free(buf3);
     316           1 :   tor_free(buf4);
     317           1 : }
     318             : 
     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
     332             : };

Generated by: LCOV version 1.14