]> git.sur5r.net Git - openldap/blob - libraries/liblutil/entropy.c
07b4c83b5f9e8092e732108a497ed0115d70bc2f
[openldap] / libraries / liblutil / entropy.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <ac/string.h>
10 #include <ac/time.h>
11
12 #ifdef HAVE_WINCRYPT_H
13 #include <wincrypt.h>
14 #endif
15 #ifdef HAVE_PROCESS_H
16 #include <process.h>
17 #endif
18
19 #include <fcntl.h>
20
21 #include <lutil.h>
22 #include <lutil_md5.h>
23
24 /*
25  * lutil_entropy() provides nbytes of entropy in buf.
26  * Quality offerred is suitable for one-time uses, such as "once" keys.
27  */
28 int lutil_entropy( char *buf, int nbytes )
29 {
30         if( nbytes < 0 ) return -1;
31         if( nbytes == 0 ) return 0;
32
33 #ifdef URANDOM_DEVICE
34         /* Linux and *BSD offer a urandom device */
35         {
36                 int rc, fd;
37
38                 fd = open( URANDOM_DEVICE, O_RDONLY );
39
40                 if( fd < 0 ) return -1;
41
42                 rc = read( fd, buf, nbytes );
43                 close(fd);
44
45                 /* should return nbytes */
46                 if( rc < nbytes ) return -1;
47
48                 return 0;
49         }
50 #elif PROV_RSA_FULL
51         {
52                 /* Not used since _WIN32_WINNT not set... */
53                 HCRYPTPROV hProv = 0;
54
55                 /* Get handle to user default provider */
56                 if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
57                    return -1;
58                 }
59
60                 /* Generate random initialization vector */
61                 if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) {
62                    return -1;
63                 }
64
65                 /* Release provider handle */
66                 if(hProv != 0) CryptReleaseContext(hProv, 0);
67
68                 return 0;
69         }
70 #else
71         {
72                 /* based upon Phil Karn's "practical randomness" idea
73                  * but implementation 100% OpenLDAP.  So don't blame Phil. */
74                 /* worse case is this is a MD5 hash of a counter, if
75                  *      MD5 is a strong cryptographic hash, this should
76                  *      be fairly resistant to attack
77                  */
78                 static int counter = 0;
79                 int n;
80
81                 struct rdata_s {
82                         int counter;
83
84                         char *buf;
85                         struct rdata_s *stack;
86
87                         pid_t   pid;
88
89 #ifdef HAVE_GETTIMEOFDAY
90                         struct timeval *tv;
91 #else
92                         time_t  time;
93 #endif
94                         unsigned long   junk;
95                 } rdata;
96
97                 /* make sure rdata differs for each process */
98                 rdata.pid = getpid();
99
100                 /* make sure rdata differs for each program */
101                 rdata.buf = buf;
102                 rdata.stack = &rdata;
103
104                 for( n = 0; n < nbytes; n += 16 ) {
105                         struct lutil_MD5Context ctx;
106                         char digest[16];
107
108                         /* hopefully has good resolution */
109 #ifdef HAVE_GETTIMEOFDAY
110                         (void) gettimeofday( &rdata.tv, sizeof( rdata.tv ) );
111 #else
112                         (void) time( &rdata.time );
113 #endif
114
115                         /* make sure rdata differs */
116                         rdata.counter = ++counter;
117                         rdata.pid++;
118                         rdata.junk++;
119
120                         lutil_MD5Init( &ctx );
121                         lutil_MD5Update( &ctx, (char *) &rdata, sizeof( rdata ) );
122                         lutil_MD5Final( digest, &ctx );
123
124                         memcpy( &buf[n], digest,
125                                 nbytes - n > 16 ? 16 : nbytes - n );
126                 }
127
128                 return 0;
129         }
130 #endif
131         return -1;
132 }