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