mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Refactor strong os-RNG into its own function
Previously, we only used the strong OS entropy source as part of seeding OpenSSL's RNG. But with curve25519, we'll have occasion to want to generate some keys using extremely-good entopy, as well as the means to do so. So let's! This patch refactors the OS-entropy wrapper into its own crypto_strongest_rand() function, and makes our new curve25519_secret_key_generate function try it as appropriate.
This commit is contained in:
parent
4d36eafd74
commit
25c05cb747
@ -2344,22 +2344,16 @@ seed_weak_rng(void)
|
|||||||
tor_init_weak_random(seed);
|
tor_init_weak_random(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Seed OpenSSL's random number generator with bytes from the operating
|
/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
|
||||||
* system. <b>startup</b> should be true iff we have just started Tor and
|
* storing it into <b>out</b>.
|
||||||
* have not yet allocated a bunch of fds. Return 0 on success, -1 on failure.
|
|
||||||
*/
|
*/
|
||||||
int
|
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
|
#ifdef _WIN32
|
||||||
unsigned char buf[ADD_ENTROPY];
|
|
||||||
static int provider_set = 0;
|
static int provider_set = 0;
|
||||||
static HCRYPTPROV provider;
|
static HCRYPTPROV provider;
|
||||||
#else
|
#else
|
||||||
char buf[ADD_ENTROPY];
|
|
||||||
static const char *filenames[] = {
|
static const char *filenames[] = {
|
||||||
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
|
"/dev/srandom", "/dev/urandom", "/dev/random", NULL
|
||||||
};
|
};
|
||||||
@ -2367,58 +2361,77 @@ crypto_seed_rng(int startup)
|
|||||||
size_t n;
|
size_t n;
|
||||||
#endif
|
#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
|
#ifdef _WIN32
|
||||||
if (!provider_set) {
|
if (!provider_set) {
|
||||||
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
|
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
|
||||||
CRYPT_VERIFYCONTEXT)) {
|
CRYPT_VERIFYCONTEXT)) {
|
||||||
if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
|
if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
|
||||||
log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
|
log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
|
||||||
return rand_poll_status ? 0 : -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
provider_set = 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.");
|
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;
|
return 0;
|
||||||
#else
|
#else
|
||||||
for (i = 0; filenames[i]; ++i) {
|
for (i = 0; filenames[i]; ++i) {
|
||||||
fd = open(filenames[i], O_RDONLY, 0);
|
fd = open(filenames[i], O_RDONLY, 0);
|
||||||
if (fd<0) continue;
|
if (fd<0) continue;
|
||||||
log_info(LD_CRYPTO, "Seeding RNG from \"%s\"", filenames[i]);
|
log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
|
||||||
n = read_all(fd, buf, sizeof(buf), 0);
|
n = read_all(fd, (char*)out, out_len, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
if (n != sizeof(buf)) {
|
if (n != out_len) {
|
||||||
log_warn(LD_CRYPTO,
|
log_warn(LD_CRYPTO,
|
||||||
"Error reading from entropy source (read only %lu bytes).",
|
"Error reading from entropy source (read only %lu bytes).",
|
||||||
(unsigned long)n);
|
(unsigned long)n);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
RAND_seed(buf, (int)sizeof(buf));
|
|
||||||
memwipe(buf, 0, sizeof(buf));
|
|
||||||
seed_weak_rng();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_warn(LD_CRYPTO, "Cannot seed RNG -- no entropy source found.");
|
log_warn(LD_CRYPTO, "Cannot get strong entropy: no entropy source found.");
|
||||||
return rand_poll_status ? 0 : -1;
|
return -1;
|
||||||
#endif
|
#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
|
/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
|
||||||
* success, -1 on failure.
|
* success, -1 on failure.
|
||||||
*/
|
*/
|
||||||
|
@ -252,6 +252,7 @@ int crypto_expand_key_material_rfc5869_sha256(
|
|||||||
/* random numbers */
|
/* random numbers */
|
||||||
int crypto_seed_rng(int startup);
|
int crypto_seed_rng(int startup);
|
||||||
int crypto_rand(char *to, size_t n);
|
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);
|
int crypto_rand_int(unsigned int max);
|
||||||
uint64_t crypto_rand_uint64(uint64_t max);
|
uint64_t crypto_rand_uint64(uint64_t max);
|
||||||
double crypto_rand_double(void);
|
double crypto_rand_double(void);
|
||||||
|
@ -59,9 +59,18 @@ void
|
|||||||
curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
|
curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
|
||||||
int extra_strong)
|
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[0] &= 248;
|
||||||
key_out->secret_key[31] &= 127;
|
key_out->secret_key[31] &= 127;
|
||||||
key_out->secret_key[31] |= 64;
|
key_out->secret_key[31] |= 64;
|
||||||
|
@ -993,7 +993,7 @@ test_crypto_curve25519_wrappers(void *arg)
|
|||||||
|
|
||||||
/* Test a simple handshake, serializing and deserializing some stuff. */
|
/* Test a simple handshake, serializing and deserializing some stuff. */
|
||||||
curve25519_secret_key_generate(&seckey1, 0);
|
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(&pubkey1, &seckey1);
|
||||||
curve25519_public_key_generate(&pubkey2, &seckey2);
|
curve25519_public_key_generate(&pubkey2, &seckey2);
|
||||||
test_assert(curve25519_public_key_is_ok(&pubkey1));
|
test_assert(curve25519_public_key_is_ok(&pubkey1));
|
||||||
|
Loading…
Reference in New Issue
Block a user