xref: /optee_os/core/lib/libtomcrypt/src/prngs/rng_get_bytes.c (revision 2a65ecaf7d6f855e24ce1a117fe1931f7378f82c)
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 #if defined(LTC_WIN32_BCRYPT)
86 
87 #include <windows.h>
88 #include <bcrypt.h>
89 #pragma comment(lib, "bcrypt.lib")
90 
s_rng_win32(unsigned char * buf,unsigned long len,void (* callback)(void))91 static unsigned long s_rng_win32(unsigned char *buf, unsigned long len,
92                                void (*callback)(void))
93 {
94    LTC_UNUSED_PARAM(callback);
95 
96    return BCRYPT_SUCCESS(BCryptGenRandom(NULL, (PUCHAR)buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG)) ? len : 0;
97 }
98 
99 #else
100 
101 #ifndef _WIN32_WINNT
102   #define _WIN32_WINNT 0x0501
103 #endif
104 #ifndef WINVER
105   #define WINVER 0x0501
106 #endif
107 
108 #define WIN32_LEAN_AND_MEAN
109 #include <windows.h>
110 #include <wincrypt.h>
111 
s_rng_win32(unsigned char * buf,unsigned long len,void (* callback)(void))112 static unsigned long s_rng_win32(unsigned char *buf, unsigned long len,
113                                void (*callback)(void))
114 {
115    LTC_UNUSED_PARAM(callback);
116 
117    static HCRYPTPROV hProv = 0;
118    if (hProv == 0) {
119       HCRYPTPROV h = 0;
120       if (!CryptAcquireContextW(&h, NULL, MS_DEF_PROV_W, PROV_RSA_FULL,
121                                 (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
122           !CryptAcquireContextW(&h, NULL, MS_DEF_PROV_W, PROV_RSA_FULL,
123                                 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
124          return 0;
125       }
126       hProv = h;
127    }
128 
129    return CryptGenRandom(hProv, (DWORD)len, (BYTE *)buf) == TRUE ? len : 0;
130 }
131 #endif /* Old WIN32 versions */
132 #endif /* WIN32 */
133 
134 /**
135   Read the system RNG
136   @param out       Destination
137   @param outlen    Length desired (octets)
138   @param callback  Pointer to void function to act as "callback" when RNG is slow.  This can be NULL
139   @return Number of octets read
140 */
rng_get_bytes(unsigned char * out,unsigned long outlen,void (* callback)(void))141 unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen,
142                             void (*callback)(void))
143 {
144    unsigned long x;
145 
146    LTC_ARGCHK(out != NULL);
147 
148 #ifdef LTC_PRNG_ENABLE_LTC_RNG
149    if (ltc_rng) {
150       x = ltc_rng(out, outlen, callback);
151       if (x != 0) {
152          return x;
153       }
154    }
155 #endif
156 
157 #if defined(_WIN32) || defined(_WIN32_WCE)
158    x = s_rng_win32(out, outlen, callback); if (x != 0) { return x; }
159 #elif defined(LTC_DEVRANDOM)
160    x = s_rng_nix(out, outlen, callback);   if (x != 0) { return x; }
161 #endif
162 #ifdef ANSI_RNG
163    x = s_rng_ansic(out, outlen, callback); if (x != 0) { return x; }
164 #endif
165    return 0;
166 }
167 #endif /* #ifdef LTC_RNG_GET_BYTES */
168