3 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
11 #include <ac/unistd.h>
20 #include <lutil_md5.h>
23 * lutil_entropy() provides nbytes of entropy in buf.
24 * Quality offerred is suitable for one-time uses, such as "once" keys.
25 * Values may not be suitable for multi-time uses.
27 * Note: Callers are encouraged to provide additional bytes of
28 * of entropy in the buf argument. This information is used in
29 * fallback mode to improve the quality of bytes returned.
31 * This routinue should be extended to support additional sources
34 int lutil_entropy( unsigned char *buf, ber_len_t nbytes )
36 if( nbytes == 0 ) return 0;
39 #define URANDOM_NREADS 4
40 /* Linux and *BSD offer a urandom device */
44 fd = open( URANDOM_DEVICE, O_RDONLY );
46 if( fd < 0 ) return -1;
49 rc = read( fd, buf, nbytes );
55 if( ++n >= URANDOM_NREADS ) break;
56 } while( nbytes > 0 );
59 return nbytes > 0 ? -1 : 0;
63 /* Not used since _WIN32_WINNT not set... */
66 /* Get handle to user default provider */
67 if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
71 /* Generate random initialization vector */
72 if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) {
76 /* Release provider handle */
77 if(hProv != 0) CryptReleaseContext(hProv, 0);
83 /* based upon Phil Karn's "practical randomness" idea
84 * but implementation 100% OpenLDAP. So don't blame Phil.
86 * Worse case is that this is a MD5 hash of a counter, if
87 * MD5 is a strong cryptographic hash, this should be fairly
92 * the caller may need to provide external synchronization OR
93 * provide entropy (in buf) to ensure quality results as
94 * access to this counter may not be atomic.
96 static int counter = 0;
103 struct rdata_s *stack;
107 #ifdef HAVE_GETTIMEOFDAY
113 unsigned long junk; /* purposely not initialized */
116 /* make sure rdata differs for each process */
117 rdata.pid = getpid();
119 /* make sure rdata differs for each program */
121 rdata.stack = &rdata;
123 for( n = 0; n < nbytes; n += 16 ) {
124 struct lutil_MD5Context ctx;
127 /* poor resolution */
128 #ifdef HAVE_GETTIMEOFDAY
129 (void) gettimeofday( &rdata.tv, NULL );
131 (void) time( &rdata.time );
134 /* make sure rdata differs */
135 rdata.counter = ++counter;
139 lutil_MD5Init( &ctx );
140 lutil_MD5Update( &ctx, (unsigned char *) &rdata, sizeof( rdata ) );
142 /* allow caller to provided additional entropy */
143 lutil_MD5Update( &ctx, buf, nbytes );
145 lutil_MD5Final( digest, &ctx );
147 AC_MEMCPY( &buf[n], digest,
148 nbytes - n >= 16 ? 16 : nbytes - n );