
commit 7186e2a94361e29188ba43837e244683ce7fbf04 Merge: 7e7188c 3843c66 Author: Nick Mathewson <nickm@torproject.org> Date: Thu Dec 10 09:02:10 2015 -0500 Merge remote-tracking branch 'public/feature17694_strongest_027' changes/bug17694_strongest | 6 +++++ src/common/crypto.c | 44 +++++++++++++++++++++++++++++++++-- src/common/crypto.h | 2 +- src/common/crypto_curve25519.c | 17 ++++---------- src/common/crypto_ed25519.c | 4 +++- src/ext/ed25519/donna/ed25519_tor.c | 3 +-- src/ext/ed25519/ref10/randombytes.h | 2 +- 7 files changed, 59 insertions(+), 19 deletions(-) diff --cc src/common/crypto.c index 5569ec7,1897946..816423a --- a/src/common/crypto.c +++ b/src/common/crypto.c @@@ -2477,54 -2338,45 +2477,91 @@@ crypto_strongest_rand_fallback(uint8_t } /** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, + * storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum + * request size of 256 bytes is imposed. + */ +int - crypto_strongest_rand(uint8_t *out, size_t out_len) ++crypto_strongest_rand_raw(uint8_t *out, size_t out_len) +{ + static const size_t sanity_min_size = 16; + static const int max_attempts = 3; + tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE); + + /* For buffers >= 16 bytes (128 bits), we sanity check the output by + * zero filling the buffer and ensuring that it actually was at least + * partially modified. + * + * Checking that any individual byte is non-zero seems like it would + * fail too often (p = out_len * 1/256) for comfort, but this is an + * "adjust according to taste" sort of check. + */ + memwipe(out, 0, out_len); + for (int i = 0; i < max_attempts; i++) { + /* Try to use the syscall/OS favored mechanism to get strong entropy. */ + if (crypto_strongest_rand_syscall(out, out_len) != 0) { + /* Try to use the less-favored mechanism to get strong entropy. */ + if (crypto_strongest_rand_fallback(out, out_len) != 0) { + /* Welp, we tried. Hopefully the calling code terminates the process + * since we're basically boned without good entropy. + */ + log_warn(LD_CRYPTO, + "Cannot get strong entropy: no entropy source found."); + return -1; + } + } + + if ((out_len < sanity_min_size) || !tor_mem_is_zero((char*)out, out_len)) + return 0; + } + + /* We tried max_attempts times to fill a buffer >= 128 bits long, + * and each time it returned all '0's. Either the system entropy + * source is busted, or the user should go out and buy a ticket to + * every lottery on the planet. + */ + log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer."); + return -1; +} + ++/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, + * storing it into <b>out</b>. + */ + void + crypto_strongest_rand(uint8_t *out, size_t out_len) + { + const unsigned DLEN = SHA512_DIGEST_LENGTH; + /* We're going to hash DLEN bytes from the system RNG together with some + * bytes from the openssl PRNG, in order to yield DLEN bytes. + */ + uint8_t inp[DLEN*2]; + uint8_t tmp[DLEN]; + tor_assert(out); + while (out_len) { + crypto_rand((char*) inp, DLEN); + if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) { + log_err(LD_CRYPTO, "Failed to load strong entropy when generating an " + "important key. Exiting."); + /* Die with an assertion so we get a stack trace. */ + tor_assert(0); + } + if (out_len >= DLEN) { + SHA512(inp, sizeof(inp), out); + out += DLEN; + out_len -= DLEN; + } else { + SHA512(inp, sizeof(inp), tmp); + memcpy(out, tmp, out_len); + out += DLEN; + out_len -= DLEN; + break; + } + } + memwipe(tmp, 0, sizeof(tmp)); + memwipe(inp, 0, sizeof(inp)); + } + /** Seed OpenSSL's random number generator with bytes from the operating - * system. <b>startup</b> should be true iff we have just started Tor and - * have not yet allocated a bunch of fds. Return 0 on success, -1 on failure. + * system. Return 0 on success, -1 on failure. */ int crypto_seed_rng(void)