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 */
20static 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
57static 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
99static 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*/
127unsigned 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