]> pd.if.org Git - uuid/blob - rng.c
Initial commit
[uuid] / rng.c
1 /*
2  * Adaped from libtomcrypt by Tom St Denis.
3  *
4  * by Nathan Wagner, and released into the public domain
5  */
6
7 #include <stdio.h>
8
9 #define LTC_ARGCHK(x)
10 #define TRY_URANDOM_FIRST 1
11
12 #ifndef WIN32
13 #define LTC_DEVRANDOM 1
14 #endif
15
16 #ifdef LTC_DEVRANDOM
17 /* on *NIX read /dev/random */
18 static unsigned long rng_nix(unsigned char *buf, unsigned long len) {
19 #ifdef LTC_NO_FILE
20         return 0;
21 #else
22         FILE           *f;
23         unsigned long   x;
24 #ifdef TRY_URANDOM_FIRST
25         f = fopen("/dev/urandom", "rb");
26         if (f == NULL)
27 #endif
28                 f = fopen("/dev/random", "rb");
29
30         if (f == NULL) {
31                 return 0;
32         }
33         /* disable buffering */
34         if (setvbuf(f, NULL, _IONBF, 0) != 0) {
35                 fclose(f);
36                 return 0;
37         }
38         x = (unsigned long) fread(buf, 1, (size_t) len, f);
39         fclose(f);
40         return x;
41 #endif
42 }
43
44 #endif
45
46 /* TODO remove this.  It's too slow really (I think) */
47 /* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */
48 #if defined(CLOCKS_PER_SEC) && !defined(WINCE)
49
50 #define ANSI_RNG
51
52 static unsigned long rng_ansic(unsigned char *buf, unsigned long len) {
53         clock_t         t1;
54         int             l, acc, bits, a, b;
55
56         if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) {
57                 return 0;
58         }
59         l = len;
60         bits = 8;
61         acc = a = b = 0;
62         while (len--) {
63                 while (bits--) {
64                         do {
65                                 t1 = XCLOCK();
66                                 while (t1 == XCLOCK())
67                                         a ^= 1;
68                                 t1 = XCLOCK();
69                                 while (t1 == XCLOCK())
70                                         b ^= 1;
71                         } while (a == b);
72                         acc = (acc << 1) | a;
73                 }
74                 *buf++ = acc;
75                 acc = 0;
76                 bits = 8;
77         }
78         acc = bits = a = b = 0;
79         return l;
80 }
81
82 #endif
83
84 /* Try the Microsoft CSP */
85 #if defined(WIN32) || defined(WINCE)
86 #warning using WIN32
87 #define _WIN32_WINNT 0x0400
88 #ifdef WINCE
89 #define UNDER_CE
90 #define ARM
91 #endif
92 #include <windows.h>
93 #include <wincrypt.h>
94
95 static unsigned long rng_win32(unsigned char *buf, unsigned long len) {
96         HCRYPTPROV      hProv = 0;
97
98         if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
99                             (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
100             !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
101               CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
102                 return 0;
103
104         if (CryptGenRandom(hProv, len, buf) == TRUE) {
105                 CryptReleaseContext(hProv, 0);
106                 return len;
107         } else {
108                 CryptReleaseContext(hProv, 0);
109                 return 0;
110         }
111 }
112
113 #endif
114
115 unsigned long   pd_uuid_rng_get_bytes(unsigned char *out, unsigned long outlen) {
116         unsigned long   x;
117
118         LTC_ARGCHK(out != NULL);
119
120 #if defined(LTC_DEVRANDOM)
121         x = rng_nix(out, outlen);
122         if (x != 0) {
123                 return x;
124         }
125 #endif
126 #ifdef WIN32
127         x = rng_win32(out, outlen);
128         if (x != 0) {
129                 return x;
130         }
131 #endif
132 #ifdef ANSI_RNG
133         x = rng_ansic(out, outlen);
134         if (x != 0) {
135                 return x;
136         }
137 #endif
138         return 0;
139 }