libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / libsodium / src / libsodium / randombytes / salsa20 / randombytes_salsa20_random.c
blobb5c8e889f36cf224ccd349100e977c98c980c9cc
2 #include <sys/types.h>
3 #include <sys/time.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
15 #include "crypto_core_salsa20.h"
16 #include "crypto_auth_hmacsha512256.h"
17 #include "crypto_stream_salsa20.h"
18 #include "randombytes.h"
19 #include "randombytes_salsa20_random.h"
20 #include "utils.h"
22 #ifdef _WIN32
23 # include <Windows.h>
24 # include <Wincrypt.h>
25 # include <sys/timeb.h>
26 #endif
28 #define SALSA20_RANDOM_BLOCK_SIZE crypto_core_salsa20_OUTPUTBYTES
29 #define SHA512_BLOCK_SIZE 128U
30 #define SHA512_MIN_PAD_SIZE (1U + 16U)
31 #define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1])
33 typedef struct Salsa20Random_ {
34 unsigned char key[crypto_stream_salsa20_KEYBYTES];
35 unsigned char rnd32[SALSA20_RANDOM_BLOCK_SIZE];
36 uint64_t nonce;
37 size_t rnd32_outleft;
38 pid_t pid;
39 #ifdef _WIN32
40 HCRYPTPROV hcrypt_prov;
41 #endif
42 int random_data_source_fd;
43 bool initialized;
44 } Salsa20Random;
46 static Salsa20Random stream = {
47 _SODIUM_C99(.random_data_source_fd =) -1,
48 _SODIUM_C99(.rnd32_outleft =) (size_t) 0U,
49 _SODIUM_C99(.initialized =) 0
52 static uint64_t
53 sodium_hrtime(void)
55 struct timeval tv;
56 uint64_t ts = (uint64_t) 0U;
57 int ret;
59 #ifdef _WIN32
60 struct _timeb tb;
62 _ftime(&tb);
63 tv.tv_sec = (long) tb.time;
64 tv.tv_usec = ((int) tb.millitm) * 1000;
65 ret = 0;
66 #else
67 ret = gettimeofday(&tv, NULL);
68 #endif
69 assert(ret == 0);
70 if (ret == 0) {
71 ts = (uint64_t) tv.tv_sec * 1000000U + (uint64_t) tv.tv_usec;
73 return ts;
76 #ifndef _WIN32
77 static ssize_t
78 safe_read(const int fd, void * const buf_, size_t count)
80 unsigned char *buf = (unsigned char *) buf_;
81 ssize_t readnb;
83 do {
84 while ((readnb = read(fd, buf, count)) < (ssize_t) 0 &&
85 errno == EINTR);
86 if (readnb < (ssize_t) 0) {
87 return readnb;
89 if (readnb == (ssize_t) 0) {
90 break;
92 count -= (size_t) readnb;
93 buf += readnb;
94 } while (count > (ssize_t) 0);
96 return (ssize_t) (buf - (unsigned char *) buf_);
98 #endif
100 #ifndef _WIN32
101 static int
102 randombytes_salsa20_random_random_dev_open(void)
104 static const char * const devices[] = {
105 # ifndef USE_BLOCKING_RANDOM
106 "/dev/arandom", "/dev/urandom",
107 # endif
108 "/dev/random", NULL
110 const char * const *device = devices;
112 do {
113 if (access(*device, F_OK | R_OK) == 0) {
114 return open(*device, O_RDONLY);
116 device++;
117 } while (*device != NULL);
119 return -1;
122 static void
123 randombytes_salsa20_random_init(void)
125 stream.nonce = sodium_hrtime();
126 assert(stream.nonce != (uint64_t) 0U);
128 if ((stream.random_data_source_fd =
129 randombytes_salsa20_random_random_dev_open()) == -1) {
130 abort();
134 #else /* _WIN32 */
136 static void
137 randombytes_salsa20_random_init(void)
139 stream.nonce = sodium_hrtime();
140 assert(stream.nonce != (uint64_t) 0U);
142 if (! CryptAcquireContext(&stream.hcrypt_prov, NULL, NULL,
143 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
144 abort();
147 #endif
149 void
150 randombytes_salsa20_random_stir(void)
152 const unsigned char s[crypto_auth_hmacsha512256_KEYBYTES] = {
153 'T', 'h', 'i', 's', 'I', 's', 'J', 'u', 's', 't', 'A', 'T',
154 'h', 'i', 'r', 't', 'y', 'T', 'w', 'o', 'B', 'y', 't', 'e',
155 's', 'S', 'e', 'e', 'd', '.', '.', '.'
157 unsigned char m0[crypto_auth_hmacsha512256_BYTES +
158 2U * SHA512_BLOCK_SIZE - SHA512_MIN_PAD_SIZE];
159 unsigned char *k0 = m0 + crypto_auth_hmacsha512256_BYTES;
160 size_t i;
161 size_t sizeof_k0 = sizeof m0 - crypto_auth_hmacsha512256_BYTES;
163 memset(stream.rnd32, 0, sizeof stream.rnd32);
164 stream.rnd32_outleft = (size_t) 0U;
165 if (stream.initialized == 0) {
166 randombytes_salsa20_random_init();
167 stream.initialized = 1;
169 #ifndef _WIN32
170 if (safe_read(stream.random_data_source_fd, m0,
171 sizeof m0) != (ssize_t) sizeof m0) {
172 abort();
174 #else /* _WIN32 */
175 if (! CryptGenRandom(stream.hcrypt_prov, sizeof m0, m0)) {
176 abort();
178 #endif
179 COMPILER_ASSERT(sizeof stream.key == crypto_auth_hmacsha512256_BYTES);
180 crypto_auth_hmacsha512256(stream.key, k0, sizeof_k0, s);
181 COMPILER_ASSERT(sizeof stream.key <= sizeof m0);
182 for (i = (size_t) 0U; i < sizeof stream.key; i++) {
183 stream.key[i] ^= m0[i];
185 sodium_memzero(m0, sizeof m0);
188 static void
189 randombytes_salsa20_random_stir_if_needed(void)
191 const pid_t pid = getpid();
193 if (stream.initialized == 0 || stream.pid != pid) {
194 stream.pid = pid;
195 randombytes_salsa20_random_stir();
199 static uint32_t
200 randombytes_salsa20_random_getword(void)
202 uint32_t val;
203 int ret;
205 COMPILER_ASSERT(sizeof stream.rnd32 >= sizeof val);
206 COMPILER_ASSERT(sizeof stream.rnd32 % sizeof val == (size_t) 0U);
207 if (stream.rnd32_outleft <= (size_t) 0U) {
208 randombytes_salsa20_random_stir_if_needed();
209 COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
210 ret = crypto_stream_salsa20((unsigned char *) stream.rnd32,
211 (unsigned long long) sizeof stream.rnd32,
212 (unsigned char *) &stream.nonce,
213 stream.key);
214 assert(ret == 0);
215 stream.nonce++;
216 stream.rnd32_outleft = sizeof stream.rnd32;
218 stream.rnd32_outleft -= sizeof val;
219 memcpy(&val, &stream.rnd32[stream.rnd32_outleft], sizeof val);
221 return val;
225 randombytes_salsa20_random_close(void)
227 int ret = -1;
229 #ifndef _WIN32
230 if (stream.random_data_source_fd != -1 &&
231 close(stream.random_data_source_fd) == 0) {
232 stream.random_data_source_fd = -1;
233 stream.initialized = 0;
234 ret = 0;
236 #else /* _WIN32 */
237 if (stream.initialized != 0 &&
238 CryptReleaseContext(stream.hcrypt_prov, 0)) {
239 stream.initialized = 0;
240 ret = 0;
242 #endif
243 return ret;
246 uint32_t
247 randombytes_salsa20_random(void)
249 return randombytes_salsa20_random_getword();
252 void
253 randombytes_salsa20_random_buf(void * const buf, const size_t size)
255 int ret;
257 randombytes_salsa20_random_stir_if_needed();
258 COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES);
259 #ifdef ULONG_LONG_MAX
260 assert(size <= ULONG_LONG_MAX);
261 #endif
262 ret = crypto_stream_salsa20((unsigned char *) buf, (unsigned long long) size,
263 (unsigned char *) &stream.nonce,
264 stream.key);
265 assert(ret == 0);
266 stream.nonce++;
270 * randombytes_salsa20_random_uniform() derives from OpenBSD's arc4random_uniform()
271 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
274 uint32_t
275 randombytes_salsa20_random_uniform(const uint32_t upper_bound)
277 uint32_t min;
278 uint32_t r;
280 if (upper_bound < 2) {
281 return 0;
283 min = (uint32_t) (-upper_bound % upper_bound);
284 for (;;) {
285 r = randombytes_salsa20_random();
286 if (r >= min) {
287 break;
290 return r % upper_bound;
293 const char *
294 randombytes_salsa20_implementation_name(void)
296 return "salsa20";
299 struct randombytes_implementation randombytes_salsa20_implementation = {
300 _SODIUM_C99(.implementation_name =) randombytes_salsa20_implementation_name,
301 _SODIUM_C99(.random =) randombytes_salsa20_random,
302 _SODIUM_C99(.stir =) randombytes_salsa20_random_stir,
303 _SODIUM_C99(.uniform =) randombytes_salsa20_random_uniform,
304 _SODIUM_C99(.buf =) randombytes_salsa20_random_buf,
305 _SODIUM_C99(.close =) randombytes_salsa20_random_close