Mention battery-backed cache under hardware selection options.
[PostgreSQL.git] / contrib / pgcrypto / random.c
blob2c09d18dfd0ca3c46b619b270f39ea9483e77b73
1 /*
2 * random.c
3 * Acquire randomness from system. For seeding RNG.
5 * Copyright (c) 2001 Marko Kreen
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * $PostgreSQL$
32 #include "postgres.h"
34 #include "px.h"
36 /* how many bytes to ask from system random provider */
37 #define RND_BYTES 32
40 * Try to read from /dev/urandom or /dev/random on these OS'es.
42 * The list can be pretty liberal, as the device not existing
43 * is expected event.
45 #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
46 || defined(__NetBSD__) || defined(__DragonFly__) \
47 || defined(__darwin__) || defined(__SOLARIS__) \
48 || defined(__hpux) || defined(__HPUX__) \
49 || defined(__CYGWIN__) || defined(_AIX)
51 #define TRY_DEV_RANDOM
53 #include <fcntl.h>
54 #include <unistd.h>
56 static int
57 safe_read(int fd, void *buf, size_t count)
59 int done = 0;
60 char *p = buf;
61 int res;
63 while (count)
65 res = read(fd, p, count);
66 if (res <= 0)
68 if (errno == EINTR)
69 continue;
70 return PXE_DEV_READ_ERROR;
72 p += res;
73 done += res;
74 count -= res;
76 return done;
79 static uint8 *
80 try_dev_random(uint8 *dst)
82 int fd;
83 int res;
85 fd = open("/dev/urandom", O_RDONLY, 0);
86 if (fd == -1)
88 fd = open("/dev/random", O_RDONLY, 0);
89 if (fd == -1)
90 return dst;
92 res = safe_read(fd, dst, RND_BYTES);
93 close(fd);
94 if (res > 0)
95 dst += res;
96 return dst;
98 #endif
101 * Try to find randomness on Windows
103 #ifdef WIN32
105 #define TRY_WIN32_GENRAND
106 #define TRY_WIN32_PERFC
108 #include <windows.h>
109 #include <wincrypt.h>
112 * this function is from libtomcrypt
114 * try to use Microsoft crypto API
116 static uint8 *
117 try_win32_genrand(uint8 *dst)
119 int res;
120 HCRYPTPROV h = 0;
122 res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
123 (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
124 if (!res)
125 res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
126 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET);
127 if (!res)
128 return dst;
130 res = CryptGenRandom(h, RND_BYTES, dst);
131 if (res == TRUE)
132 dst += RND_BYTES;
134 CryptReleaseContext(h, 0);
135 return dst;
138 static uint8 *
139 try_win32_perfc(uint8 *dst)
141 int res;
142 LARGE_INTEGER time;
144 res = QueryPerformanceCounter(&time);
145 if (!res)
146 return dst;
148 memcpy(dst, &time, sizeof(time));
149 return dst + sizeof(time);
151 #endif /* WIN32 */
155 * If we are not on Windows, then hopefully we are
156 * on a unix-like system. Use the usual suspects
157 * for randomness.
159 #ifndef WIN32
161 #define TRY_UNIXSTD
163 #include <sys/types.h>
164 #include <sys/time.h>
165 #include <time.h>
166 #include <unistd.h>
169 * Everything here is predictible, only needs some patience.
171 * But there is a chance that the system-specific functions
172 * did not work. So keep faith and try to slow the attacker down.
174 static uint8 *
175 try_unix_std(uint8 *dst)
177 pid_t pid;
178 int x;
179 PX_MD *md;
180 struct timeval tv;
181 int res;
183 /* process id */
184 pid = getpid();
185 memcpy(dst, (uint8 *) &pid, sizeof(pid));
186 dst += sizeof(pid);
188 /* time */
189 gettimeofday(&tv, NULL);
190 memcpy(dst, (uint8 *) &tv, sizeof(tv));
191 dst += sizeof(tv);
193 /* pointless, but should not hurt */
194 x = random();
195 memcpy(dst, (uint8 *) &x, sizeof(x));
196 dst += sizeof(x);
198 /* let's be desperate */
199 res = px_find_digest("sha1", &md);
200 if (res >= 0)
202 uint8 *ptr;
203 uint8 stack[8192];
204 int alloc = 32 * 1024;
206 px_md_update(md, stack, sizeof(stack));
207 ptr = px_alloc(alloc);
208 px_md_update(md, ptr, alloc);
209 px_free(ptr);
211 px_md_finish(md, dst);
212 px_md_free(md);
214 dst += 20;
217 return dst;
219 #endif
222 * try to extract some randomness for initial seeding
224 * dst should have room for 1024 bytes.
226 unsigned
227 px_acquire_system_randomness(uint8 *dst)
229 uint8 *p = dst;
231 #ifdef TRY_DEV_RANDOM
232 p = try_dev_random(p);
233 #endif
234 #ifdef TRY_WIN32_GENRAND
235 p = try_win32_genrand(p);
236 #endif
237 #ifdef TRY_WIN32_PERFC
238 p = try_win32_perfc(p);
239 #endif
240 #ifdef TRY_UNIXSTD
241 p = try_unix_std(p);
242 #endif
243 return p - dst;