-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrandom.c
132 lines (123 loc) · 3.54 KB
/
random.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** Generate good random numbers ...
* Get them from the OS if possible
*
* (c) Kurt Garloff <[email protected]>, 10/2014
* License: GPL v2 or v3
*/
#include "random.h"
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
typedef unsigned int __u32;
#ifdef HAVE_LINUX_RANDOM_H
#include <linux/random.h>
#endif
#ifdef HAVE_SYS_RANDOM_H
#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 28
#warning Compile with -target linux-aarch64-android28 or -target linux-arm-android28
#endif
#include <sys/random.h>
#endif
static void msleep(unsigned int msecs)
{
struct timespec ts1, ts2;
ts1.tv_sec = msecs/1000;
ts1.tv_nsec= (msecs%1000)*1000000;
nanosleep(&ts1, &ts2);
}
#if (defined(__x86_64__) || defined(__i386__)) && !defined(NO_RDRND)
unsigned int rdrand32();
#else
#define BSWAP32(x) ((x<<24) | ((x<<8)&0x00ff0000) | ((x>>8)&0x0000ff00) | (x>>24))
#endif
unsigned int random_getseedval32()
{
struct timeval tv;
gettimeofday(&tv, NULL);
#if (defined(__x86_64__) || defined(__i386__)) && !defined(NO_RDRND)
unsigned int hwrnd = rdrand32();
#else
/* Some randomness due to ASLR ... */
unsigned int hwrnd = BSWAP32((unsigned int)(unsigned long)&random_getseedval32);
#endif
return (tv.tv_usec << 12) ^ tv.tv_sec ^ getpid() ^ hwrnd;
}
#if defined(HAVE_GETENTROPY) && !defined(HAVE_GETRANDOM)
static int getrandom(void *buf, size_t buflen, unsigned int flags)
{
/* Problem: We can't differentiate b/w urandom and random(GRND_RANDOM) */
int err = getentropy(buf, buflen);
if (err < 0)
return err;
else
return buflen;
}
#define GRND_RANDOM 2
#define HAVE_GETRANDOM 2
#endif
#ifdef HAVE_GETRANDOM
#define READ_RAND(fd, buf, ln, flg) getrandom(buf, ln, flg)
#define RAND_CLOSE(fd) do {} while(0)
#else
#define READ_RAND(fd, buf, ln, flg) read(fd, buf, ln)
#define RAND_CLOSE(fd) close(fd)
#endif
/* Functions to generate N bytes of good or really good random numbers
* Notes:
* - We use getrandom() and getentropy() if available, otherwise fall back to
* /dev/random or /dev/urandom which works only Linux
* (TODO: Use CryptGenRandom and/or RtlGenRandom/s_rand on Windows.)
* - We mix in the bytes from the libc rand() function, not because it really adds
* entropy, but to make observation from the outside (think hypervisors ...) a bit
* harder. (TODO: Could do better on BSD with arc4random() ... )
*/
unsigned int random_bytes(unsigned char* buf, unsigned int ln, unsigned char nourand)
{
srand(random_getseedval32());
rand();
#ifndef HAVE_GETRANDOM
const char* rdfnm = (nourand? "/dev/random": "/dev/urandom");
int fd = open(rdfnm, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "FATAL: Can't open %s for random numbers\n", rdfnm);
raise(SIGQUIT);
}
#else
unsigned int flg = nourand? GRND_RANDOM: 0;
#endif
unsigned i;
for (i = 0; i < (ln+3)/4; ++i) {
unsigned int rnd;
int err = READ_RAND(fd, &rnd, 4, flg);
if (nourand && err < 4) {
fprintf(stderr, "WARN: Short on entropy, generate some more!\n");
msleep(100);
if (err > 0)
err += READ_RAND(fd, ((unsigned char*)(&rnd))+err, 4-err, flg);
else
err = READ_RAND(fd, &rnd, 4, flg);
}
if (err != 4) {
fprintf(stderr, "FATAL: Error getting random numbers (%i): %i %s\n",
nourand, err, strerror(errno));
RAND_CLOSE(fd);
raise(SIGQUIT);
}
rnd ^= rand();
if (4*i+3 < ln)
((unsigned int*)buf)[i] = rnd;
else
memcpy(buf+4*i, &rnd, ln-4*i);
}
RAND_CLOSE(fd);
return ln;
}