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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/* Statistical tests for arc4random-related functions.
Copyright (C) 2022-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <array_length.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <support/check.h>
enum
{
arc4random_key_size = 32
};
struct key
{
unsigned char data[arc4random_key_size];
};
/* With 12,000 keys, the probability that a byte in a predetermined
position does not have a predetermined value in all generated keys
is about 4e-21. The probability that this happens with any of the
16 * 256 possible byte position/values is 1.6e-17. This results in
an acceptably low false-positive rate. */
enum { key_count = 12000 };
static struct key keys[key_count];
/* Used to perform the distribution check. */
static int byte_counts[arc4random_key_size][256];
/* Bail out after this many failures. */
enum { failure_limit = 100 };
static void
find_stuck_bytes (bool (*func) (unsigned char *key))
{
memset (&keys, 0xcc, sizeof (keys));
int failures = 0;
for (int key = 0; key < key_count; ++key)
{
while (true)
{
if (func (keys[key].data))
break;
++failures;
if (failures >= failure_limit)
{
printf ("warning: bailing out after %d failures\n", failures);
return;
}
}
}
printf ("info: key generation finished with %d failures\n", failures);
memset (&byte_counts, 0, sizeof (byte_counts));
for (int key = 0; key < key_count; ++key)
for (int pos = 0; pos < arc4random_key_size; ++pos)
++byte_counts[pos][keys[key].data[pos]];
for (int pos = 0; pos < arc4random_key_size; ++pos)
for (int byte = 0; byte < 256; ++byte)
if (byte_counts[pos][byte] == 0)
{
support_record_failure ();
printf ("error: byte %d never appeared at position %d\n", byte, pos);
}
}
/* Test adapter for arc4random. */
static bool
generate_arc4random (unsigned char *key)
{
uint32_t words[arc4random_key_size / 4];
_Static_assert (sizeof (words) == arc4random_key_size, "sizeof (words)");
for (int i = 0; i < array_length (words); ++i)
words[i] = arc4random ();
memcpy (key, &words, arc4random_key_size);
return true;
}
/* Test adapter for arc4random_buf. */
static bool
generate_arc4random_buf (unsigned char *key)
{
arc4random_buf (key, arc4random_key_size);
return true;
}
/* Test adapter for arc4random_uniform. */
static bool
generate_arc4random_uniform (unsigned char *key)
{
for (int i = 0; i < arc4random_key_size; ++i)
key[i] = arc4random_uniform (256);
return true;
}
/* Test adapter for arc4random_uniform with argument 257. This means
that byte 0 happens more often, but we do not perform such a
statistical check, so the test will still pass */
static bool
generate_arc4random_uniform_257 (unsigned char *key)
{
for (int i = 0; i < arc4random_key_size; ++i)
key[i] = arc4random_uniform (257);
return true;
}
static int
do_test (void)
{
puts ("info: arc4random implementation test");
find_stuck_bytes (generate_arc4random);
puts ("info: arc4random_buf implementation test");
find_stuck_bytes (generate_arc4random_buf);
puts ("info: arc4random_uniform implementation test");
find_stuck_bytes (generate_arc4random_uniform);
puts ("info: arc4random_uniform implementation test (257 variant)");
find_stuck_bytes (generate_arc4random_uniform_257);
return 0;
}
#include <support/test-driver.c>
|