1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2 *
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
5 *
6 * The library is free for all purposes without any express
7 * guarantee it works.
8 *
9 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
10 */
11 #include "tomcrypt.h"
12
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 #ifdef DEVRANDOM
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 return 0;
25 #else
26 FILE *f;
27 unsigned long x;
28 #ifdef TRY_URANDOM_FIRST
29 f = fopen("/dev/urandom", "rb");
30 if (f == NULL)
31 #endif /* TRY_URANDOM_FIRST */
32 f = fopen("/dev/random", "rb");
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 /* DEVRANDOM */
51
52 /* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */
53 #if defined(CLOCKS_PER_SEC) && !defined(WINCE)
54
55 #define ANSI_RNG
56
rng_ansic(unsigned char * buf,unsigned long len,void (* callback)(void))57 static unsigned long rng_ansic(unsigned char *buf, unsigned long len,
58 void (*callback)(void))
59 {
60 clock_t t1;
61 int l, acc, bits, a, b;
62
63 if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) {
64 return 0;
65 }
66
67 l = len;
68 bits = 8;
69 acc = a = b = 0;
70 while (len--) {
71 if (callback != NULL) callback();
72 while (bits--) {
73 do {
74 t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1;
75 t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1;
76 } while (a == b);
77 acc = (acc << 1) | a;
78 }
79 *buf++ = acc;
80 acc = 0;
81 bits = 8;
82 }
83 acc = bits = a = b = 0;
84 return l;
85 }
86
87 #endif
88
89 /* Try the Microsoft CSP */
90 #if defined(WIN32) || defined(WINCE)
91 #define _WIN32_WINNT 0x0400
92 #ifdef WINCE
93 #define UNDER_CE
94 #define ARM
95 #endif
96 #include <windows.h>
97 #include <wincrypt.h>
98
rng_win32(unsigned char * buf,unsigned long len,void (* callback)(void))99 static unsigned long rng_win32(unsigned char *buf, unsigned long len,
100 void (*callback)(void))
101 {
102 HCRYPTPROV hProv = 0;
103 if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
104 (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
105 !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
106 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
107 return 0;
108
109 if (CryptGenRandom(hProv, len, buf) == TRUE) {
110 CryptReleaseContext(hProv, 0);
111 return len;
112 } else {
113 CryptReleaseContext(hProv, 0);
114 return 0;
115 }
116 }
117
118 #endif /* WIN32 */
119
120 /**
121 Read the system RNG
122 @param out Destination
123 @param outlen Length desired (octets)
124 @param callback Pointer to void function to act as "callback" when RNG is slow. This can be NULL
125 @return Number of octets read
126 */
rng_get_bytes(unsigned char * out,unsigned long outlen,void (* callback)(void))127 unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen,
128 void (*callback)(void))
129 {
130 unsigned long x;
131
132 LTC_ARGCHK(out != NULL);
133
134 #if defined(DEVRANDOM)
135 x = rng_nix(out, outlen, callback); if (x != 0) { return x; }
136 #endif
137 #ifdef WIN32
138 x = rng_win32(out, outlen, callback); if (x != 0) { return x; }
139 #endif
140 #ifdef ANSI_RNG
141 x = rng_ansic(out, outlen, callback); if (x != 0) { return x; }
142 #endif
143 return 0;
144 }
145
146 /* $Source: /cvs/libtom/libtomcrypt/src/prngs/rng_get_bytes.c,v $ */
147 /* $Revision: 1.5 $ */
148 /* $Date: 2006/12/06 02:01:29 $ */
149