1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4
5 #ifdef LTC_RNG_GET_BYTES
6 /**
7 @file rng_get_bytes.c
8 portable way to get secure random bits to feed a PRNG (Tom St Denis)
9 */
10
11 #if defined(LTC_DEVRANDOM) && !defined(_WIN32)
12 /* on *NIX read /dev/random */
s_rng_nix(unsigned char * buf,unsigned long len,void (* callback)(void))13 static unsigned long s_rng_nix(unsigned char *buf, unsigned long len,
14 void (*callback)(void))
15 {
16 #ifdef LTC_NO_FILE
17 LTC_UNUSED_PARAM(callback);
18 LTC_UNUSED_PARAM(buf);
19 LTC_UNUSED_PARAM(len);
20 return 0;
21 #else
22 FILE *f;
23 unsigned long x;
24 LTC_UNUSED_PARAM(callback);
25 #ifdef LTC_TRY_URANDOM_FIRST
26 f = fopen("/dev/urandom", "rb");
27 if (f == NULL) {
28 f = fopen("/dev/random", "rb");
29 }
30 #else
31 f = fopen("/dev/random", "rb");
32 #endif /* LTC_TRY_URANDOM_FIRST */
33
34 if (f == NULL) {
35 return 0;
36 }
37
38 /* disable buffering */
39 if (setvbuf(f, NULL, _IONBF, 0) != 0) {
40 fclose(f);
41 return 0;
42 }
43
44 x = (unsigned long)fread(buf, 1, (size_t)len, f);
45 fclose(f);
46 return x;
47 #endif /* LTC_NO_FILE */
48 }
49
50 #endif /* LTC_DEVRANDOM */
51
52 #if !defined(_WIN32_WCE)
53
54 #define ANSI_RNG
55
s_rng_ansic(unsigned char * buf,unsigned long len,void (* callback)(void))56 static unsigned long s_rng_ansic(unsigned char *buf, unsigned long len,
57 void (*callback)(void))
58 {
59 clock_t t1;
60 int l, acc, bits, a, b;
61
62 l = len;
63 bits = 8;
64 acc = a = b = 0;
65 while (len--) {
66 if (callback != NULL) callback();
67 while (bits--) {
68 do {
69 t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1;
70 t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1;
71 } while (a == b);
72 acc = (acc << 1) | a;
73 }
74 *buf++ = acc;
75 acc = 0;
76 bits = 8;
77 }
78 return l;
79 }
80
81 #endif
82
83 /* Try the Microsoft CSP */
84 #if defined(_WIN32) || defined(_WIN32_WCE)
85 #ifndef _WIN32_WINNT
86 #define _WIN32_WINNT 0x0400
87 #endif
88 #ifdef _WIN32_WCE
89 #define UNDER_CE
90 #define ARM
91 #endif
92
93 #define WIN32_LEAN_AND_MEAN
94 #include <windows.h>
95 #include <wincrypt.h>
96
s_rng_win32(unsigned char * buf,unsigned long len,void (* callback)(void))97 static unsigned long s_rng_win32(unsigned char *buf, unsigned long len,
98 void (*callback)(void))
99 {
100 HCRYPTPROV hProv = 0;
101 LTC_UNUSED_PARAM(callback);
102 if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
103 (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
104 !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
105 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
106 return 0;
107
108 if (CryptGenRandom(hProv, len, buf) == TRUE) {
109 CryptReleaseContext(hProv, 0);
110 return len;
111 } else {
112 CryptReleaseContext(hProv, 0);
113 return 0;
114 }
115 }
116
117 #endif /* WIN32 */
118
119 /**
120 Read the system RNG
121 @param out Destination
122 @param outlen Length desired (octets)
123 @param callback Pointer to void function to act as "callback" when RNG is slow. This can be NULL
124 @return Number of octets read
125 */
rng_get_bytes(unsigned char * out,unsigned long outlen,void (* callback)(void))126 unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen,
127 void (*callback)(void))
128 {
129 unsigned long x;
130
131 LTC_ARGCHK(out != NULL);
132
133 #ifdef LTC_PRNG_ENABLE_LTC_RNG
134 if (ltc_rng) {
135 x = ltc_rng(out, outlen, callback);
136 if (x != 0) {
137 return x;
138 }
139 }
140 #endif
141
142 #if defined(_WIN32) || defined(_WIN32_WCE)
143 x = s_rng_win32(out, outlen, callback); if (x != 0) { return x; }
144 #elif defined(LTC_DEVRANDOM)
145 x = s_rng_nix(out, outlen, callback); if (x != 0) { return x; }
146 #endif
147 #ifdef ANSI_RNG
148 x = s_rng_ansic(out, outlen, callback); if (x != 0) { return x; }
149 #endif
150 return 0;
151 }
152 #endif /* #ifdef LTC_RNG_GET_BYTES */
153