1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 8 #include <nxt_main.h> 9 10 11 /* 12 * The pseudorandom generator based on OpenBSD arc4random. Although it is 13 * usually stated that arc4random uses RC4 pseudorandom generation algorithm 14 * they are actually different in nxt_random_add(). 15 */ 16 17 18 #define NXT_RANDOM_KEY_SIZE 128 19 20 21 nxt_inline void nxt_random_start_schedule(nxt_random_t *r); 22 static void nxt_random_stir(nxt_random_t *r); 23 static void nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len); 24 nxt_inline uint8_t nxt_random_byte(nxt_random_t *r); 25 26 27 void 28 nxt_random_init(nxt_random_t *r) 29 { 30 nxt_random_start_schedule(r); 31 32 nxt_random_stir(r); 33 } 34 35 36 nxt_inline void 37 nxt_random_start_schedule(nxt_random_t *r) 38 { 39 nxt_uint_t i; 40 41 r->i = 0; 42 r->j = 0; 43 44 for (i = 0; i < 256; i++) { 45 r->s[i] = i; 46 } 47 } 48 49 50 static void 51 nxt_random_stir(nxt_random_t *r) 52 { 53 int fd; 54 ssize_t n; 55 struct timeval tv; 56 union { 57 uint32_t value[4]; 58 u_char bytes[NXT_RANDOM_KEY_SIZE]; 59 } key; 60 61 #if (NXT_HAVE_GETRANDOM) 62 63 n = getrandom(&key, NXT_RANDOM_KEY_SIZE, 0); 64 65 #elif (NXT_HAVE_LINUX_SYS_GETRANDOM) 66 67 /* Linux 3.17 SYS_getrandom. */ 68 69 n = syscall(SYS_getrandom, &key, NXT_RANDOM_KEY_SIZE, 0); 70 71 #elif (NXT_HAVE_GETENTROPY || NXT_HAVE_GETENTROPY_SYS_RANDOM) 72 73 n = 0; 74 75 if (getentropy(&key, NXT_RANDOM_KEY_SIZE) == 0) { 76 n = NXT_RANDOM_KEY_SIZE; 77 } 78 79 #else 80 81 n = 0; 82 83 #endif 84 85 if (n != NXT_RANDOM_KEY_SIZE) { 86 fd = open("/dev/urandom", O_RDONLY); 87 88 if (fd >= 0) { 89 n = read(fd, &key, NXT_RANDOM_KEY_SIZE); 90 (void) close(fd); 91 } 92 } 93 94 if (n != NXT_RANDOM_KEY_SIZE) { 95 (void) gettimeofday(&tv, NULL); 96 97 /* XOR with stack garbage. */ 98 99 key.value[0] ^= tv.tv_usec; 100 key.value[1] ^= tv.tv_sec; 101 key.value[2] ^= nxt_pid; 102 key.value[3] ^= (uintptr_t) nxt_thread_tid(NULL); 103 } 104 105 nxt_random_add(r, key.bytes, NXT_RANDOM_KEY_SIZE); 106 107 /* Drop the first 3072 bytes. */ 108 for (n = 3072; n != 0; n--) { 109 (void) nxt_random_byte(r); 110 } 111 112 /* Stir again after 1,600,000 bytes. */ 113 r->count = 400000; 114 } 115 116 117 static void 118 nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len) 119 { 120 uint8_t val; 121 uint32_t n; 122 123 for (n = 0; n < 256; n++) { 124 val = r->s[r->i]; 125 r->j += val + key[n % len]; 126 127 r->s[r->i] = r->s[r->j]; 128 r->s[r->j] = val; 129 130 r->i++; 131 } 132 133 /* This index is not decremented in RC4 algorithm. */ 134 r->i--; 135 136 r->j = r->i; 137 } 138 139 140 uint32_t 141 nxt_random(nxt_random_t *r) 142 { 143 uint32_t val; 144 145 r->count--; 146 147 if (r->count <= 0) { 148 nxt_random_stir(r); 149 } 150 151 val = nxt_random_byte(r) << 24; 152 val |= nxt_random_byte(r) << 16; 153 val |= nxt_random_byte(r) << 8; 154 val |= nxt_random_byte(r); 155 156 return val; 157 } 158 159 160 nxt_inline uint8_t 161 nxt_random_byte(nxt_random_t *r) 162 { 163 uint8_t si, sj; 164 165 r->i++; 166 si = r->s[r->i]; 167 r->j += si; 168 169 sj = r->s[r->j]; 170 r->s[r->i] = sj; 171 r->s[r->j] = si; 172 173 si += sj; 174 175 return r->s[si]; 176 } 177 178 179 #if (NXT_TESTS) 180 181 nxt_int_t 182 nxt_random_test(nxt_thread_t *thr) 183 { 184 nxt_uint_t n; 185 nxt_random_t r; 186 187 nxt_random_start_schedule(&r); 188 189 r.count = 400000; 190 191 nxt_random_add(&r, (u_char *) "arc4random", nxt_length("arc4random")); 192 193 /* 194 * Test arc4random() numbers. 195 * RC4 pseudorandom numbers would be 0x4642AFC3 and 0xBAF0FFF0. 196 */ 197 198 if (nxt_random(&r) == 0xD6270B27) { 199 200 for (n = 100000; n != 0; n--) { 201 (void) nxt_random(&r); 202 } 203 204 if (nxt_random(&r) == 0x6FCAE186) { 205 nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test passed"); 206 207 return NXT_OK; 208 } 209 } 210 211 nxt_log_error(NXT_LOG_NOTICE, thr->log, "arc4random test failed"); 212 213 return NXT_ERROR; 214 } 215 216 #endif 217