/** * Helper: refill the seed bytes and output buffer of <b>rng</b>, using * the input seed bytes as input (key and IV) for the stream cipher. * * If the n_till_reseed counter has reached zero, mix more random bytes into * the seed before refilling the buffer. **/ static void crypto_fast_rng_refill(crypto_fast_rng_t *rng) { if (rng->n_till_reseed-- == 0) { /* It's time to reseed the RNG. We'll do this by using our XOF to mix the * old value for the seed with some additional bytes from * crypto_strongest_rand(). */ crypto_xof_t *xof = crypto_xof_new(); crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN); { uint8_t seedbuf[SEED_LEN]; crypto_strongest_rand(seedbuf, SEED_LEN); crypto_xof_add_bytes(xof, seedbuf, SEED_LEN); memwipe(seedbuf, 0, SEED_LEN); } crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN); crypto_xof_free(xof); rng->n_till_reseed = RESEED_AFTER; } /* Now fill rng->buf with output from our stream cipher, initialized from * that seed value. */ crypto_cipher_t *c = cipher_from_seed(rng->buf.seed); memset(&rng->buf, 0, sizeof(rng->buf)); crypto_cipher_crypt_inplace(c, (char*)&rng->buf, sizeof(rng->buf)); crypto_cipher_free(c); rng->bytes_left = sizeof(rng->buf.bytes); }
/** * Initialize and return a new fast PRNG, using a strong random seed. * * Note that this object is NOT thread-safe. If you need a thread-safe * prng, use crypto_rand(), or wrap this in a mutex. **/ crypto_fast_rng_t * crypto_fast_rng_new(void) { uint8_t seed[SEED_LEN]; crypto_strongest_rand(seed, sizeof(seed)); crypto_fast_rng_t *result = crypto_fast_rng_new_from_seed(seed); memwipe(seed, 0, sizeof(seed)); return result; }
static void test_crypto_rng_strongest(void *arg) { const char *how = arg; int broken = 0; if (how == NULL) { ; } else if (!strcmp(how, "nosyscall")) { break_strongest_rng_syscall = 1; } else if (!strcmp(how, "nofallback")) { break_strongest_rng_fallback = 1; } else if (!strcmp(how, "broken")) { broken = break_strongest_rng_syscall = break_strongest_rng_fallback = 1; } #define N 128 uint8_t combine_and[N]; uint8_t combine_or[N]; int i, j; memset(combine_and, 0xff, N); memset(combine_or, 0, N); for (i = 0; i < 100; ++i) { /* 2^-100 chances just don't happen. */ uint8_t output[N]; memset(output, 0, N); if (how == NULL) { /* this one can't fail. */ crypto_strongest_rand(output, sizeof(output)); } else { int r = crypto_strongest_rand_raw(output, sizeof(output)); if (r == -1) { if (broken) { goto done; /* we're fine. */ } /* This function is allowed to break, but only if it always breaks. */ tt_int_op(i, OP_EQ, 0); tt_skip(); } else { tt_assert(! broken); } } for (j = 0; j < N; ++j) { combine_and[j] &= output[j]; combine_or[j] |= output[j]; } } for (j = 0; j < N; ++j) { tt_int_op(combine_and[j], OP_EQ, 0); tt_int_op(combine_or[j], OP_EQ, 0xff); } done: ; #undef N }
/** * Generate CURVE25519_SECKEY_LEN random bytes in <b>out</b>. If * <b>extra_strong</b> is true, this key is possibly going to get used more * than once, so use a better-than-usual RNG. Return 0 on success, -1 on * failure. * * This function does not adjust the output of the RNG at all; the will caller * will need to clear or set the appropriate bits to make curve25519 work. */ int curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong) { if (extra_strong) crypto_strongest_rand(out, CURVE25519_SECKEY_LEN); else crypto_rand((char*)out, CURVE25519_SECKEY_LEN); return 0; }
int ed25519_donna_seckey(unsigned char *sk) { ed25519_secret_key seed; crypto_strongest_rand(seed, 32); ed25519_extsk(sk, seed); memwipe(seed, 0, sizeof(seed)); return 0; }
/** * Initialize a new ed25519 secret key in <b>seckey_out</b>. If * <b>extra_strong</b>, take the RNG inputs directly from the operating * system. Return 0 on success, -1 on failure. */ int ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out, int extra_strong) { int r; uint8_t seed[32]; if (! extra_strong || crypto_strongest_rand(seed, sizeof(seed)) < 0) crypto_rand((char*)seed, sizeof(seed)); r = get_ed_impl()->seckey_expand(seckey_out->seckey, seed); memwipe(seed, 0, sizeof(seed)); return r < 0 ? -1 : 0; }
/** * Generate CURVE25519_SECKEY_LEN random bytes in <b>out</b>. If * <b>extra_strong</b> is true, this key is possibly going to get used more * than once, so use a better-than-usual RNG. Return 0 on success, -1 on * failure. * * This function does not adjust the output of the RNG at all; the will caller * will need to clear or set the appropriate bits to make curve25519 work. */ int curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong) { uint8_t k_tmp[CURVE25519_SECKEY_LEN]; if (crypto_rand((char*)out, CURVE25519_SECKEY_LEN) < 0) return -1; if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) { /* If they asked for extra-strong entropy and we have some, use it as an * HMAC key to improve not-so-good entropy rather than using it directly, * just in case the extra-strong entropy is less amazing than we hoped. */ crypto_hmac_sha256((char*) out, (const char *)k_tmp, sizeof(k_tmp), (const char *)out, CURVE25519_SECKEY_LEN); } memwipe(k_tmp, 0, sizeof(k_tmp)); return 0; }