diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/crypto.c | 77 | ||||
-rw-r--r-- | src/common/crypto.h | 1 | ||||
-rw-r--r-- | src/common/crypto_curve25519.c | 13 | ||||
-rw-r--r-- | src/test/test_crypto.c | 2 |
4 files changed, 58 insertions, 35 deletions
diff --git a/src/common/crypto.c b/src/common/crypto.c index 2147738b4..4d61f2d93 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -2344,22 +2344,16 @@ seed_weak_rng(void) tor_init_weak_random(seed); } -/** 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. +/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, + * storing it into <b>out</b>. */ int -crypto_seed_rng(int startup) +crypto_strongest_rand(uint8_t *out, size_t out_len) { - int rand_poll_status = 0; - - /* local variables */ #ifdef _WIN32 - unsigned char buf[ADD_ENTROPY]; static int provider_set = 0; static HCRYPTPROV provider; #else - char buf[ADD_ENTROPY]; static const char *filenames[] = { "/dev/srandom", "/dev/urandom", "/dev/random", NULL }; @@ -2367,58 +2361,77 @@ crypto_seed_rng(int startup) size_t n; #endif - /* OpenSSL has a RAND_poll function that knows about more kinds of - * entropy than we do. We'll try calling that, *and* calling our own entropy - * functions. If one succeeds, we'll accept the RNG as seeded. */ - if (startup || RAND_POLL_IS_SAFE) { - rand_poll_status = RAND_poll(); - if (rand_poll_status == 0) - log_warn(LD_CRYPTO, "RAND_poll() failed."); - } - #ifdef _WIN32 if (!provider_set) { if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) { log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]"); - return rand_poll_status ? 0 : -1; + return -1; } } provider_set = 1; } - if (!CryptGenRandom(provider, sizeof(buf), buf)) { + if (!CryptGenRandom(provider, out_len, out)) { log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI."); - return rand_poll_status ? 0 : -1; + return -1; } - RAND_seed(buf, sizeof(buf)); - memwipe(buf, 0, sizeof(buf)); - seed_weak_rng(); + return 0; #else for (i = 0; filenames[i]; ++i) { fd = open(filenames[i], O_RDONLY, 0); if (fd<0) continue; - log_info(LD_CRYPTO, "Seeding RNG from \"%s\"", filenames[i]); - n = read_all(fd, buf, sizeof(buf), 0); + log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); + n = read_all(fd, (char*)out, out_len, 0); close(fd); - if (n != sizeof(buf)) { + if (n != out_len) { log_warn(LD_CRYPTO, "Error reading from entropy source (read only %lu bytes).", (unsigned long)n); return -1; } - RAND_seed(buf, (int)sizeof(buf)); - memwipe(buf, 0, sizeof(buf)); - seed_weak_rng(); + return 0; } - log_warn(LD_CRYPTO, "Cannot seed RNG -- no entropy source found."); - return rand_poll_status ? 0 : -1; + log_warn(LD_CRYPTO, "Cannot get strong entropy: no entropy source found."); + return -1; #endif } +/** 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. + */ +int +crypto_seed_rng(int startup) +{ + int rand_poll_ok = 0, load_entropy_ok = 0; + uint8_t buf[ADD_ENTROPY]; + + /* OpenSSL has a RAND_poll function that knows about more kinds of + * entropy than we do. We'll try calling that, *and* calling our own entropy + * functions. If one succeeds, we'll accept the RNG as seeded. */ + if (startup || RAND_POLL_IS_SAFE) { + rand_poll_ok = RAND_poll(); + if (rand_poll_ok == 0) + log_warn(LD_CRYPTO, "RAND_poll() failed."); + } + + load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf)); + if (load_entropy_ok) { + RAND_seed(buf, sizeof(buf)); + } + + memwipe(buf, 0, sizeof(buf)); + seed_weak_rng(); + if (rand_poll_ok || load_entropy_ok) + return 0; + else + return -1; +} + /** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on * success, -1 on failure. */ diff --git a/src/common/crypto.h b/src/common/crypto.h index 2d31e8d8b..b6e8e6c56 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -252,6 +252,7 @@ int crypto_expand_key_material_rfc5869_sha256( /* random numbers */ int crypto_seed_rng(int startup); int crypto_rand(char *to, size_t n); +int crypto_strongest_rand(uint8_t *out, size_t out_len); int crypto_rand_int(unsigned int max); uint64_t crypto_rand_uint64(uint64_t max); double crypto_rand_double(void); diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c index 1985e8af2..ce0cd0d60 100644 --- a/src/common/crypto_curve25519.c +++ b/src/common/crypto_curve25519.c @@ -59,9 +59,18 @@ void curve25519_secret_key_generate(curve25519_secret_key_t *key_out, int extra_strong) { - (void)extra_strong; + uint8_t k_tmp[CURVE25519_SECKEY_LEN]; - crypto_rand((char*)key_out->secret_key, 32); + crypto_rand((char*)key_out->secret_key, CURVE25519_SECKEY_LEN); + 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 entopy rather than using it directly, + * just in case the extra-strong entropy is less amazing than we hoped. */ + crypto_hmac_sha256((char *)key_out->secret_key, + (const char *)k_tmp, sizeof(k_tmp), + (const char *)key_out->secret_key, CURVE25519_SECKEY_LEN); + } + memwipe(k_tmp, 0, sizeof(k_tmp)); key_out->secret_key[0] &= 248; key_out->secret_key[31] &= 127; key_out->secret_key[31] |= 64; diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 8aadd979a..2b3229aff 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -993,7 +993,7 @@ test_crypto_curve25519_wrappers(void *arg) /* Test a simple handshake, serializing and deserializing some stuff. */ curve25519_secret_key_generate(&seckey1, 0); - curve25519_secret_key_generate(&seckey2, 0); + curve25519_secret_key_generate(&seckey2, 1); curve25519_public_key_generate(&pubkey1, &seckey1); curve25519_public_key_generate(&pubkey2, &seckey2); test_assert(curve25519_public_key_is_ok(&pubkey1)); |