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