~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to contrib/pgcrypto/random.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * random.c
 
3
 *              Acquire randomness from system.  For seeding RNG.
 
4
 *
 
5
 * Copyright (c) 2001 Marko Kreen
 
6
 * All rights reserved.
 
7
 *
 
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.
 
16
 *
 
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.
 
28
 *
 
29
 * $PostgreSQL$
 
30
 */
 
31
 
 
32
#include "postgres.h"
 
33
 
 
34
#include "px.h"
 
35
 
 
36
/* how many bytes to ask from system random provider */
 
37
#define RND_BYTES  32
 
38
 
 
39
/*
 
40
 * Try to read from /dev/urandom or /dev/random on these OS'es.
 
41
 *
 
42
 * The list can be pretty liberal, as the device not existing
 
43
 * is expected event.
 
44
 */
 
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)
 
50
 
 
51
#define TRY_DEV_RANDOM
 
52
 
 
53
#include <fcntl.h>
 
54
#include <unistd.h>
 
55
 
 
56
static int
 
57
safe_read(int fd, void *buf, size_t count)
 
58
{
 
59
        int                     done = 0;
 
60
        char       *p = buf;
 
61
        int                     res;
 
62
 
 
63
        while (count)
 
64
        {
 
65
                res = read(fd, p, count);
 
66
                if (res <= 0)
 
67
                {
 
68
                        if (errno == EINTR)
 
69
                                continue;
 
70
                        return PXE_DEV_READ_ERROR;
 
71
                }
 
72
                p += res;
 
73
                done += res;
 
74
                count -= res;
 
75
        }
 
76
        return done;
 
77
}
 
78
 
 
79
static uint8 *
 
80
try_dev_random(uint8 *dst)
 
81
{
 
82
        int                     fd;
 
83
        int                     res;
 
84
 
 
85
        fd = open("/dev/urandom", O_RDONLY, 0);
 
86
        if (fd == -1)
 
87
        {
 
88
                fd = open("/dev/random", O_RDONLY, 0);
 
89
                if (fd == -1)
 
90
                        return dst;
 
91
        }
 
92
        res = safe_read(fd, dst, RND_BYTES);
 
93
        close(fd);
 
94
        if (res > 0)
 
95
                dst += res;
 
96
        return dst;
 
97
}
 
98
#endif
 
99
 
 
100
/*
 
101
 * Try to find randomness on Windows
 
102
 */
 
103
#ifdef WIN32
 
104
 
 
105
#define TRY_WIN32_GENRAND
 
106
#define TRY_WIN32_PERFC
 
107
 
 
108
#include <windows.h>
 
109
#include <wincrypt.h>
 
110
 
 
111
/*
 
112
 * this function is from libtomcrypt
 
113
 *
 
114
 * try to use Microsoft crypto API
 
115
 */
 
116
static uint8 *
 
117
try_win32_genrand(uint8 *dst)
 
118
{
 
119
        int                     res;
 
120
        HCRYPTPROV      h = 0;
 
121
 
 
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;
 
129
 
 
130
        res = CryptGenRandom(h, RND_BYTES, dst);
 
131
        if (res == TRUE)
 
132
                dst += RND_BYTES;
 
133
 
 
134
        CryptReleaseContext(h, 0);
 
135
        return dst;
 
136
}
 
137
 
 
138
static uint8 *
 
139
try_win32_perfc(uint8 *dst)
 
140
{
 
141
        int                     res;
 
142
        LARGE_INTEGER time;
 
143
 
 
144
        res = QueryPerformanceCounter(&time);
 
145
        if (!res)
 
146
                return dst;
 
147
 
 
148
        memcpy(dst, &time, sizeof(time));
 
149
        return dst + sizeof(time);
 
150
}
 
151
#endif   /* WIN32 */
 
152
 
 
153
 
 
154
/*
 
155
 * If we are not on Windows, then hopefully we are
 
156
 * on a unix-like system.  Use the usual suspects
 
157
 * for randomness.
 
158
 */
 
159
#ifndef WIN32
 
160
 
 
161
#define TRY_UNIXSTD
 
162
 
 
163
#include <sys/types.h>
 
164
#include <sys/time.h>
 
165
#include <time.h>
 
166
#include <unistd.h>
 
167
 
 
168
/*
 
169
 * Everything here is predictible, only needs some patience.
 
170
 *
 
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.
 
173
 */
 
174
static uint8 *
 
175
try_unix_std(uint8 *dst)
 
176
{
 
177
        pid_t           pid;
 
178
        int                     x;
 
179
        PX_MD      *md;
 
180
        struct timeval tv;
 
181
        int                     res;
 
182
 
 
183
        /* process id */
 
184
        pid = getpid();
 
185
        memcpy(dst, (uint8 *) &pid, sizeof(pid));
 
186
        dst += sizeof(pid);
 
187
 
 
188
        /* time */
 
189
        gettimeofday(&tv, NULL);
 
190
        memcpy(dst, (uint8 *) &tv, sizeof(tv));
 
191
        dst += sizeof(tv);
 
192
 
 
193
        /* pointless, but should not hurt */
 
194
        x = random();
 
195
        memcpy(dst, (uint8 *) &x, sizeof(x));
 
196
        dst += sizeof(x);
 
197
 
 
198
        /* let's be desperate */
 
199
        res = px_find_digest("sha1", &md);
 
200
        if (res >= 0)
 
201
        {
 
202
                uint8      *ptr;
 
203
                uint8           stack[8192];
 
204
                int                     alloc = 32 * 1024;
 
205
 
 
206
                px_md_update(md, stack, sizeof(stack));
 
207
                ptr = px_alloc(alloc);
 
208
                px_md_update(md, ptr, alloc);
 
209
                px_free(ptr);
 
210
 
 
211
                px_md_finish(md, dst);
 
212
                px_md_free(md);
 
213
 
 
214
                dst += 20;
 
215
        }
 
216
 
 
217
        return dst;
 
218
}
 
219
#endif
 
220
 
 
221
/*
 
222
 * try to extract some randomness for initial seeding
 
223
 *
 
224
 * dst should have room for 1024 bytes.
 
225
 */
 
226
unsigned
 
227
px_acquire_system_randomness(uint8 *dst)
 
228
{
 
229
        uint8      *p = dst;
 
230
 
 
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;
 
244
}