Explicit is better than implicit © The Zen of Python. The nxt_thread_tid(NULL) call was used only twice in the code and such behaviour was specific to nxt_thread_tid() function.
217 lines
3.8 KiB
C
217 lines
3.8 KiB
C
|
|
/*
|
|
* Copyright (C) Igor Sysoev
|
|
* Copyright (C) NGINX, Inc.
|
|
*/
|
|
|
|
|
|
#include <nxt_main.h>
|
|
|
|
|
|
/*
|
|
* The pseudorandom generator based on OpenBSD arc4random. Although it is
|
|
* usually stated that arc4random uses RC4 pseudorandom generation algorithm
|
|
* they are actually different in nxt_random_add().
|
|
*/
|
|
|
|
|
|
#define NXT_RANDOM_KEY_SIZE 128
|
|
|
|
|
|
nxt_inline void nxt_random_start_schedule(nxt_random_t *r);
|
|
static void nxt_random_stir(nxt_random_t *r);
|
|
static void nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len);
|
|
nxt_inline uint8_t nxt_random_byte(nxt_random_t *r);
|
|
|
|
|
|
void
|
|
nxt_random_init(nxt_random_t *r)
|
|
{
|
|
nxt_random_start_schedule(r);
|
|
|
|
nxt_random_stir(r);
|
|
}
|
|
|
|
|
|
nxt_inline void
|
|
nxt_random_start_schedule(nxt_random_t *r)
|
|
{
|
|
nxt_uint_t i;
|
|
|
|
r->i = 0;
|
|
r->j = 0;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
r->s[i] = i;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_random_stir(nxt_random_t *r)
|
|
{
|
|
int fd;
|
|
ssize_t n;
|
|
struct timeval tv;
|
|
union {
|
|
uint32_t value[4];
|
|
u_char bytes[NXT_RANDOM_KEY_SIZE];
|
|
} key;
|
|
|
|
#if (NXT_HAVE_GETRANDOM)
|
|
|
|
n = getrandom(&key, NXT_RANDOM_KEY_SIZE, 0);
|
|
|
|
#elif (NXT_HAVE_LINUX_SYS_GETRANDOM)
|
|
|
|
/* Linux 3.17 SYS_getrandom. */
|
|
|
|
n = syscall(SYS_getrandom, &key, NXT_RANDOM_KEY_SIZE, 0);
|
|
|
|
#elif (NXT_HAVE_GETENTROPY || NXT_HAVE_GETENTROPY_SYS_RANDOM)
|
|
|
|
n = 0;
|
|
|
|
if (getentropy(&key, NXT_RANDOM_KEY_SIZE) == 0) {
|
|
n = NXT_RANDOM_KEY_SIZE;
|
|
}
|
|
|
|
#else
|
|
|
|
n = 0;
|
|
|
|
#endif
|
|
|
|
if (n != NXT_RANDOM_KEY_SIZE) {
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
|
|
if (fd >= 0) {
|
|
n = read(fd, &key, NXT_RANDOM_KEY_SIZE);
|
|
(void) close(fd);
|
|
}
|
|
}
|
|
|
|
if (n != NXT_RANDOM_KEY_SIZE) {
|
|
(void) gettimeofday(&tv, NULL);
|
|
|
|
/* XOR with stack garbage. */
|
|
|
|
key.value[0] ^= tv.tv_usec;
|
|
key.value[1] ^= tv.tv_sec;
|
|
key.value[2] ^= nxt_pid;
|
|
key.value[3] ^= (uintptr_t) nxt_thread_tid(nxt_thread());
|
|
}
|
|
|
|
nxt_random_add(r, key.bytes, NXT_RANDOM_KEY_SIZE);
|
|
|
|
/* Drop the first 3072 bytes. */
|
|
for (n = 3072; n != 0; n--) {
|
|
(void) nxt_random_byte(r);
|
|
}
|
|
|
|
/* Stir again after 1,600,000 bytes. */
|
|
r->count = 400000;
|
|
}
|
|
|
|
|
|
static void
|
|
nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len)
|
|
{
|
|
uint8_t val;
|
|
uint32_t n;
|
|
|
|
for (n = 0; n < 256; n++) {
|
|
val = r->s[r->i];
|
|
r->j += val + key[n % len];
|
|
|
|
r->s[r->i] = r->s[r->j];
|
|
r->s[r->j] = val;
|
|
|
|
r->i++;
|
|
}
|
|
|
|
/* This index is not decremented in RC4 algorithm. */
|
|
r->i--;
|
|
|
|
r->j = r->i;
|
|
}
|
|
|
|
|
|
uint32_t
|
|
nxt_random(nxt_random_t *r)
|
|
{
|
|
uint32_t val;
|
|
|
|
r->count--;
|
|
|
|
if (r->count <= 0) {
|
|
nxt_random_stir(r);
|
|
}
|
|
|
|
val = nxt_random_byte(r) << 24;
|
|
val |= nxt_random_byte(r) << 16;
|
|
val |= nxt_random_byte(r) << 8;
|
|
val |= nxt_random_byte(r);
|
|
|
|
return val;
|
|
}
|
|
|
|
|
|
nxt_inline uint8_t
|
|
nxt_random_byte(nxt_random_t *r)
|
|
{
|
|
uint8_t si, sj;
|
|
|
|
r->i++;
|
|
si = r->s[r->i];
|
|
r->j += si;
|
|
|
|
sj = r->s[r->j];
|
|
r->s[r->i] = sj;
|
|
r->s[r->j] = si;
|
|
|
|
si += sj;
|
|
|
|
return r->s[si];
|
|
}
|
|
|
|
|
|
#if (NXT_TESTS)
|
|
|
|
nxt_int_t
|
|
nxt_random_test(nxt_thread_t *thr)
|
|
{
|
|
nxt_uint_t n;
|
|
nxt_random_t r;
|
|
|
|
nxt_random_start_schedule(&r);
|
|
|
|
r.count = 400000;
|
|
|
|
nxt_random_add(&r, (u_char *) "arc4random", nxt_length("arc4random"));
|
|
|
|
/*
|
|
* Test arc4random() numbers.
|
|
* RC4 pseudorandom numbers would be 0x4642AFC3 and 0xBAF0FFF0.
|
|
*/
|
|
|
|
if (nxt_random(&r) == 0xD6270B27) {
|
|
|
|
for (n = 100000; n != 0; n--) {
|
|
(void) nxt_random(&r);
|
|
}
|
|
|
|
if (nxt_random(&r) == 0x6FCAE186) {
|
|
nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test passed");
|
|
|
|
return NXT_OK;
|
|
}
|
|
}
|
|
|
|
nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test failed");
|
|
|
|
return NXT_ERROR;
|
|
}
|
|
|
|
#endif
|