Changeset View
Standalone View
sys/libkern/arc4random.c
Show All 35 Lines | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/random.h> | #include <sys/random.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/time.h> | #include <sys/time.h> | ||||
#include <crypto/chacha20/chacha.h> | #include <crypto/chacha20/chacha.h> | ||||
#include <dev/random/randomdev.h> | |||||
#include <machine/cpu.h> | |||||
#define CHACHA20_RESEED_BYTES 65536 | #define CHACHA20_RESEED_BYTES 65536 | ||||
#define CHACHA20_RESEED_SECONDS 300 | #define CHACHA20_RESEED_SECONDS 300 | ||||
#define CHACHA20_KEYBYTES 32 | #define CHACHA20_KEYBYTES 32 | ||||
#define CHACHA20_BUFFER_SIZE 64 | #define CHACHA20_BUFFER_SIZE 64 | ||||
CTASSERT(CHACHA20_KEYBYTES*8 >= CHACHA_MINKEYLEN); | CTASSERT(CHACHA20_KEYBYTES*8 >= CHACHA_MINKEYLEN); | ||||
Show All 20 Lines | |||||
* Mix up the current context. | * Mix up the current context. | ||||
*/ | */ | ||||
static void | static void | ||||
chacha20_randomstir(struct chacha20_s *chacha20) | chacha20_randomstir(struct chacha20_s *chacha20) | ||||
{ | { | ||||
struct timeval tv_now; | struct timeval tv_now; | ||||
u_int8_t key[CHACHA20_KEYBYTES]; | u_int8_t key[CHACHA20_KEYBYTES]; | ||||
if (__predict_false(random_bypass_before_seeding && !is_random_seeded())) { | |||||
struct timespec ts_now; | |||||
unsigned i, j, k; | |||||
uint64_t cc; | |||||
const u_int8_t *p, *q; | |||||
if (!arc4random_bypassed_before_seeding) { | |||||
arc4random_bypassed_before_seeding = true; | |||||
if (!random_bypass_disable_warnings) | |||||
printf("arc4random: WARNING: initial seeding " | |||||
"bypassed the cryptographic random device " | |||||
"because it was not yet seeded and the " | |||||
"knob 'bypass_before_seeding' was " | |||||
"enabled.\n"); | |||||
} | |||||
/* Last ditch effort to inject something in a bad condition. */ | |||||
cc = get_cyclecount(); | |||||
getnanouptime(&ts_now); | |||||
delphij: I think 'cc' and 'ts_now' is quite closely related, is it useful to have both? | |||||
cemAuthorUnsubmitted Done Inline ActionsThey are certainly correlated; I'm not sure whether it is useful to have both. Maybe we can just drop 'ts_now', since the low order bits of cc are most likely to be non-deterministic. cem: They are certainly correlated; I'm not sure whether it is useful to have both. Maybe we can… | |||||
p = (const void *)&ts_now.tv_nsec; | |||||
q = (const void *)&cc; | |||||
for (i = 0, j = 0, k = 4; i < sizeof(key); i++) { | |||||
delphijUnsubmitted Done Inline ActionsMaybe use existing hash like SHA512_256: SHA512_256_Init(&ctx); Instead of simple XOR's? delphij: Maybe use existing hash like SHA512_256:
SHA512_256_Init(&ctx);
SHA512_256_Update(&ctx, key… | |||||
cemAuthorUnsubmitted Done Inline ActionsWhat beneficial property are you suggesting we add with the hash? I am not especially opposed to the idea (although SHA512_256 will be quite slow on e.g., MIPS) but I'm not sure if there is a specific benefit in mind? cem: What beneficial property are you suggesting we add with the hash? I am not especially opposed… | |||||
delphijUnsubmitted Done Inline ActionsIt's mostly to get more bits flipped (avalanche effect found in a cryptographic hash algorithm), and also create a slightly more computation burden for those who wants to attempt a brute-force of the possible values at boot. Timestamps have more entropy in their lower bits, but less with their higher bits; when you are stacking up some related values, it's less susceptible to cancel each other out compared to plain XOR's (note that the tv_nsec and cc sizes have a GCD of sizeof(long), by the way). You may also want to consider mixing in additional data, like __FreeBSD_version here. I don't think performance is a big concern here as the data being hashed are fairly small, and this is not a "hot" codepath. delphij: It's mostly to get more bits flipped (avalanche effect found in a cryptographic hash algorithm)… | |||||
cemAuthorUnsubmitted Done Inline ActionsOk, I'll make that change. One caveat with SHA512/256 in particular is that it is an optional module (optional crypto | geom_bde | ipsec | ipsec_support | zfs). On the other hand, vanilla SHA256 is already required by random. Do you have a strong preference for 512/256 over plain SHA2 256? I'll go ahead and make the change (planning on SHA256 for now). cem: Ok, I'll make that change. One caveat with SHA512/256 in particular is that it is an optional… | |||||
delphijUnsubmitted Not Done Inline Actions
No, I just picked up a random one which I thought is available; since it's not part of standard kernel I think we should go with SHA256 instead (and thanks for pointing it out). delphij: > Do you have a strong preference for 512/256 over plain SHA2 256?
No, I just picked up a… | |||||
key[i] ^= p[j]; | |||||
key[i] ^= q[k]; | |||||
j = (j + 1) % sizeof(ts_now.tv_nsec); | |||||
k = (k + 1) % sizeof(cc); | |||||
} | |||||
} else { | |||||
/* | /* | ||||
* If the loader(8) did not have an entropy stash from the previous | * If the loader(8) did not have an entropy stash from the | ||||
* shutdown to load, then we will block. The answer is to make sure | * previous shutdown to load, then we will block. The answer is | ||||
* there is an entropy stash at shutdown time. | * to make sure there is an entropy stash at shutdown time. | ||||
* | |||||
* On the other hand, if the random_bypass_before_seeding knob | |||||
* was set and we landed in this branch, we know this won't | |||||
* block because we know the random device is seeded. | |||||
*/ | */ | ||||
read_random(key, CHACHA20_KEYBYTES); | read_random(key, CHACHA20_KEYBYTES); | ||||
} | |||||
getmicrouptime(&tv_now); | getmicrouptime(&tv_now); | ||||
mtx_lock(&chacha20->mtx); | mtx_lock(&chacha20->mtx); | ||||
chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8); | chacha_keysetup(&chacha20->ctx, key, CHACHA20_KEYBYTES*8); | ||||
chacha_ivsetup(&chacha20->ctx, (u_char *)&tv_now.tv_sec, (u_char *)&tv_now.tv_usec); | chacha_ivsetup(&chacha20->ctx, (u_char *)&tv_now.tv_sec, (u_char *)&tv_now.tv_usec); | ||||
/* Reset for next reseed cycle. */ | /* Reset for next reseed cycle. */ | ||||
chacha20->t_reseed = tv_now.tv_sec + CHACHA20_RESEED_SECONDS; | chacha20->t_reseed = tv_now.tv_sec + CHACHA20_RESEED_SECONDS; | ||||
chacha20->numbytes = 0; | chacha20->numbytes = 0; | ||||
mtx_unlock(&chacha20->mtx); | mtx_unlock(&chacha20->mtx); | ||||
▲ Show 20 Lines • Show All 90 Lines • Show Last 20 Lines |
I think 'cc' and 'ts_now' is quite closely related, is it useful to have both?