Optionally use RDRAND to mitigate prediction of future values

if a key is compromised.
This commit is contained in:
Frank Denis 2017-11-25 21:07:05 +01:00
parent 0e0daa48b2
commit 5117b1adc5

View File

@ -24,6 +24,10 @@
# endif # endif
# include <poll.h> # include <poll.h>
#endif #endif
#ifdef HAVE_RDRAND
# pragma GCC target("rdrnd")
# include <immintrin.h>
#endif
#include "core.h" #include "core.h"
#include "crypto_core_salsa20.h" #include "crypto_core_salsa20.h"
@ -31,6 +35,7 @@
#include "private/common.h" #include "private/common.h"
#include "randombytes.h" #include "randombytes.h"
#include "randombytes_salsa20_random.h" #include "randombytes_salsa20_random.h"
#include "runtime.h"
#include "utils.h" #include "utils.h"
#ifdef _WIN32 #ifdef _WIN32
@ -63,6 +68,7 @@ typedef struct Salsa20Random_ {
int random_data_source_fd; int random_data_source_fd;
int initialized; int initialized;
int getrandom_available; int getrandom_available;
int rdrand_available;
unsigned char key[crypto_stream_salsa20_KEYBYTES]; unsigned char key[crypto_stream_salsa20_KEYBYTES];
unsigned char rnd32[16U * SALSA20_RANDOM_BLOCK_SIZE]; unsigned char rnd32[16U * SALSA20_RANDOM_BLOCK_SIZE];
uint64_t nonce; uint64_t nonce;
@ -75,7 +81,8 @@ static Salsa20Random stream = {
SODIUM_C99(.rnd32_outleft =) (size_t) 0U, SODIUM_C99(.rnd32_outleft =) (size_t) 0U,
SODIUM_C99(.random_data_source_fd =) -1, SODIUM_C99(.random_data_source_fd =) -1,
SODIUM_C99(.initialized =) 0, SODIUM_C99(.initialized =) 0,
SODIUM_C99(.getrandom_available =) 0 SODIUM_C99(.getrandom_available =) 0,
SODIUM_C99(.rdrand_available =) 0
}; };
static uint64_t static uint64_t
@ -255,6 +262,7 @@ randombytes_salsa20_random_init(void)
const int errno_save = errno; const int errno_save = errno;
stream.nonce = sodium_hrtime(); stream.nonce = sodium_hrtime();
stream.rdrand_available = sodium_runtime_has_rdrand();
assert(stream.nonce != (uint64_t) 0U); assert(stream.nonce != (uint64_t) 0U);
# ifdef HAVE_SAFE_ARC4RANDOM # ifdef HAVE_SAFE_ARC4RANDOM
@ -288,6 +296,7 @@ static void
randombytes_salsa20_random_init(void) randombytes_salsa20_random_init(void)
{ {
stream.nonce = sodium_hrtime(); stream.nonce = sodium_hrtime();
stream.rdrand_available = sodium_runtime_has_rdrand();
assert(stream.nonce != (uint64_t) 0U); assert(stream.nonce != (uint64_t) 0U);
} }
#endif #endif
@ -402,6 +411,22 @@ randombytes_salsa20_random_close(void)
return ret; return ret;
} }
/* RDRAND is only used to mitigate prediction if a key is compromised */
static void
randombytes_salsa20_random_xorhwrand(void)
{
#ifdef HAVE_RDRAND
unsigned int r;
if (stream.rdrand_available == 0) {
return;
}
(void) _rdrand32_step(&r);
* (uint32_t *) (void *)
&stream.key[crypto_stream_salsa20_KEYBYTES - 4] ^= (uint32_t) r;
#endif
}
static void static void
randombytes_salsa20_random_buf(void * const buf, const size_t size) randombytes_salsa20_random_buf(void * const buf, const size_t size)
{ {
@ -422,6 +447,7 @@ randombytes_salsa20_random_buf(void * const buf, const size_t size)
for (i = 0U; i < sizeof size; i++) { for (i = 0U; i < sizeof size; i++) {
stream.key[i] ^= ((const unsigned char *) (const void *) &size)[i]; stream.key[i] ^= ((const unsigned char *) (const void *) &size)[i];
} }
randombytes_salsa20_random_xorhwrand();
stream.nonce++; stream.nonce++;
crypto_stream_salsa20_xor(stream.key, stream.key, sizeof stream.key, crypto_stream_salsa20_xor(stream.key, stream.key, sizeof stream.key,
(unsigned char *) &stream.nonce, stream.key); (unsigned char *) &stream.nonce, stream.key);
@ -445,6 +471,7 @@ randombytes_salsa20_random(void)
stream.key); stream.key);
assert(ret == 0); assert(ret == 0);
stream.rnd32_outleft = (sizeof stream.rnd32) - (sizeof stream.key); stream.rnd32_outleft = (sizeof stream.rnd32) - (sizeof stream.key);
randombytes_salsa20_random_xorhwrand();
randombytes_salsa20_random_xorkey(&stream.rnd32[stream.rnd32_outleft]); randombytes_salsa20_random_xorkey(&stream.rnd32[stream.rnd32_outleft]);
memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof stream.key); memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof stream.key);
stream.nonce++; stream.nonce++;