Module Name: src Committed By: riastradh Date: Mon Mar 10 21:21:32 UTC 2025
Modified Files: src/lib/libc/gen: arc4random.c Log Message: arc4random(3): Add self-tests for PRNG algorithm. Independently generated by running: head -c 64 </dev/zero \ | openssl enc -chacha -20 \ -K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \ -iv -iv 00000000000000000000000000000000 \ | hexdump -C and then repeating with the first 32 bytes of output as the updated key for -K, extracting bytes [32, 32 + n) for the n-byte output in each call. To generate a diff of this commit: cvs rdiff -u -r1.46 -r1.47 src/lib/libc/gen/arc4random.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/gen/arc4random.c diff -u src/lib/libc/gen/arc4random.c:1.46 src/lib/libc/gen/arc4random.c:1.47 --- src/lib/libc/gen/arc4random.c:1.46 Sun Mar 9 18:11:55 2025 +++ src/lib/libc/gen/arc4random.c Mon Mar 10 21:21:32 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: arc4random.c,v 1.46 2025/03/09 18:11:55 riastradh Exp $ */ +/* $NetBSD: arc4random.c,v 1.47 2025/03/10 21:21:32 riastradh Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -51,7 +51,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: arc4random.c,v 1.46 2025/03/09 18:11:55 riastradh Exp $"); +__RCSID("$NetBSD: arc4random.c,v 1.47 2025/03/10 21:21:32 riastradh Exp $"); #include "namespace.h" #include "reentrant.h" @@ -319,6 +319,52 @@ crypto_prng_buf(struct crypto_prng *prng (void)explicit_memset(output, 0, sizeof output); } +static int +crypto_prng_selftest(void) +{ + const uint8_t expected[32] = { +#if _BYTE_ORDER == _LITTLE_ENDIAN +# if crypto_core_ROUNDS == 20 + 0x2b, /* first call */ + 0x2d,0x41,0xa5,0x9c,0x90,0xe4,0x1a,0x8e, /* second call */ + 0x7a,0x4d,0xcc,0xaa,0x1c,0x46,0x06,0x99, + 0x83,0xb1,0xa3,0x33,0xce,0x25,0x71,0x9e, + 0xc3,0x43,0x77,0x68,0xab,0x57, + 0x5f, /* third call */ +# else +# error crypto_core_ROUNDS other than 20 left as exercise for reader. +# endif +#elif _BYTE_ORDER == _BIG_ENDIAN +# if crypto_core_ROUNDS == 20 + 0xae, /* first call */ + 0x97,0x14,0x5a,0x05,0xad,0xa8,0x48,0xf1, /* second call */ + 0x3a,0x81,0x84,0xd7,0x05,0xda,0x20,0x5d, + 0xc0,0xef,0x86,0x65,0x98,0xbd,0xb0,0x16, + 0x1b,0xfc,0xff,0xc4,0xc2,0xfd, + 0xa0, /* third call */ +# else +# error crypto_core_ROUNDS other than 20 left as exercise for reader. +# endif +#else +# error Byte order must be little-endian or big-endian. +#endif + }; + uint8_t seed[crypto_prng_SEEDBYTES]; + struct crypto_prng prng; + uint8_t output[32]; + unsigned i; + + for (i = 0; i < __arraycount(seed); i++) + seed[i] = i; + crypto_prng_seed(&prng, seed); + crypto_prng_buf(&prng, output, 1); + crypto_prng_buf(&prng, output + 1, 30); + crypto_prng_buf(&prng, output + 31, 1); + if (memcmp(output, expected, 32) != 0) + return EIO; + return 0; +} + /* One-time stream: expand short single-use secret into long secret */ #define crypto_onetimestream_SEEDBYTES crypto_core_KEYBYTES @@ -386,6 +432,60 @@ crypto_onetimestream(const void *seed, v (void)explicit_memset(block, 0, sizeof block); } +static int +crypto_onetimestream_selftest(void) +{ + const uint8_t expected[70] = { + 0x5a, /* guard byte */ +#if _BYTE_ORDER == _LITTLE_ENDIAN +# if crypto_core_ROUNDS == 20 + 0x39,0xfd,0x2b, /* initial block */ + 0x18,0xb8,0x42,0x31,0xad,0xe6,0xa6,0xd1, + 0x13,0x61,0x5c,0x61,0xaf,0x43,0x4e,0x27, + 0xf8,0xb1,0xf3,0xf5,0xe1,0xad,0x5b,0x5c, + 0xec,0xf8,0xfc,0x12,0x2a,0x35,0x75,0x5c, + 0x72,0x08,0x08,0x6d,0xd1,0xee,0x3c,0x5d, + 0x9d,0x81,0x58,0x24,0x64,0x0e,0x00,0x3c, + 0x9b,0xa0,0xf6,0x5e,0xde,0x5d,0x59,0xce, + 0x0d,0x2a,0x4a,0x7f,0x31,0x95,0x5a,0xcd, + 0x42, /* final block */ +# else +# error crypto_core_ROUNDS other than 20 left as exercise for reader. +# endif +#elif _BYTE_ORDER == _BIG_ENDIAN +# if crypto_core_ROUNDS == 20 + 0x20,0xf0,0x66, /* initial block */ + 0xc9,0x06,0x63,0xc5,0x45,0x38,0xd1,0xb1, + 0xe6,0x3e,0xbf,0x68,0x19,0xd6,0xf1,0xbe, + 0x09,0xb9,0x49,0xc4,0xf5,0x55,0x95,0xc1, + 0x54,0x56,0xeb,0xe4,0x8c,0xa5,0xbb,0x55, + 0x17,0x89,0x8e,0x90,0x51,0x53,0xea,0x17, + 0x29,0xf5,0x7e,0xe4,0x78,0x08,0x53,0xc8, + 0x54,0xa8,0xba,0x76,0xce,0x0e,0x8d,0x2f, + 0xe1,0x07,0xc8,0x46,0x73,0x3e,0x61,0x0c, + 0x02, /* final block */ +# else +# error crypto_core_ROUNDS other than 20 left as exercise for reader. +# endif +#else +# error Byte order must be little-endian or big-endian. +#endif + 0xcc, /* guard byte */ + }; + uint8_t seed[crypto_prng_SEEDBYTES]; + uint8_t output[70] __aligned(4); + unsigned i; + + for (i = 0; i < __arraycount(seed); i++) + seed[i] = i; + output[0] = 0x5a; + output[69] = 0xcc; + crypto_onetimestream(seed, output + 1, 68); + if (memcmp(output, expected, 70) != 0) + return EIO; + return 0; +} + /* * entropy_epoch() * @@ -561,7 +661,9 @@ arc4random_initialize(void) * If the crypto software is broken, abort -- something is * severely wrong with this process image. */ - if (crypto_core_selftest() != 0) + if (crypto_core_selftest() != 0 || + crypto_prng_selftest() != 0 || + crypto_onetimestream_selftest() != 0) abort(); /*