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