1 /* entropy.c -- routines for providing pseudo-random data */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1999-2005 The OpenLDAP Foundation.
6 * Portions Copyright 1999-2003 Kurt D. Zeilenga.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
17 /* This work was initially developed by Kurt D. Zeilenga for
18 * inclusion in OpenLDAP Software based, in part, on publically
19 * available works (as noted below).
24 #include <ac/string.h>
26 #include <ac/unistd.h>
35 #include <lutil_md5.h>
38 * lutil_entropy() provides nbytes of entropy in buf.
39 * Quality offerred is suitable for one-time uses, such as "once" keys.
40 * Values may not be suitable for multi-time uses.
42 * Note: Callers are encouraged to provide additional bytes of
43 * of entropy in the buf argument. This information is used in
44 * fallback mode to improve the quality of bytes returned.
46 * This routinue should be extended to support additional sources
49 int lutil_entropy( unsigned char *buf, ber_len_t nbytes )
51 if( nbytes == 0 ) return 0;
54 #define URANDOM_NREADS 4
55 /* Linux and *BSD offer a urandom device */
59 fd = open( URANDOM_DEVICE, O_RDONLY );
61 if( fd < 0 ) return -1;
64 rc = read( fd, buf, nbytes );
70 if( ++n >= URANDOM_NREADS ) break;
71 } while( nbytes > 0 );
74 return nbytes > 0 ? -1 : 0;
78 /* Not used since _WIN32_WINNT not set... */
81 /* Get handle to user default provider */
82 if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
86 /* Generate random initialization vector */
87 if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) {
91 /* Release provider handle */
92 if(hProv != 0) CryptReleaseContext(hProv, 0);
98 /* based upon Phil Karn's "practical randomness" idea
99 * but implementation 100% OpenLDAP. So don't blame Phil.
101 * Worse case is that this is a MD5 hash of a counter, if
102 * MD5 is a strong cryptographic hash, this should be fairly
103 * resistant to attack
107 * the caller may need to provide external synchronization OR
108 * provide entropy (in buf) to ensure quality results as
109 * access to this counter may not be atomic.
111 static int counter = 0;
118 struct rdata_s *stack;
122 #ifdef HAVE_GETTIMEOFDAY
128 unsigned long junk; /* purposely not initialized */
131 /* make sure rdata differs for each process */
132 rdata.pid = getpid();
134 /* make sure rdata differs for each program */
136 rdata.stack = &rdata;
138 for( n = 0; n < nbytes; n += 16 ) {
139 struct lutil_MD5Context ctx;
140 unsigned char digest[16];
142 /* poor resolution */
143 #ifdef HAVE_GETTIMEOFDAY
144 (void) gettimeofday( &rdata.tv, NULL );
146 (void) time( &rdata.time );
149 /* make sure rdata differs */
150 rdata.counter = ++counter;
154 lutil_MD5Init( &ctx );
155 lutil_MD5Update( &ctx, (unsigned char *) &rdata, sizeof( rdata ) );
157 /* allow caller to provided additional entropy */
158 lutil_MD5Update( &ctx, buf, nbytes );
160 lutil_MD5Final( digest, &ctx );
162 AC_MEMCPY( &buf[n], digest,
163 nbytes - n >= 16 ? 16 : nbytes - n );