]> git.sur5r.net Git - openldap/blob - libraries/liblutil/entropy.c
Fix up comments.
[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  * Note:  Callers are encouraged to provide additional bytes of
29  * of entropy in the buf argument.  This information is used in
30  * fallback mode to improve the quality of bytes returned.
31  */
32 int lutil_entropy( char *buf, int nbytes )
33 {
34         if( nbytes < 0 ) return -1;
35         if( nbytes == 0 ) return 0;
36
37 #ifdef URANDOM_DEVICE
38         /* Linux and *BSD offer a urandom device */
39         {
40                 int rc, fd;
41
42                 fd = open( URANDOM_DEVICE, O_RDONLY );
43
44                 if( fd < 0 ) return -1;
45
46                 rc = read( fd, buf, nbytes );
47                 close(fd);
48
49                 /* should return nbytes */
50                 if( rc < nbytes ) return -1;
51
52                 return 0;
53         }
54 #elif PROV_RSA_FULL
55         {
56                 /* Not used since _WIN32_WINNT not set... */
57                 HCRYPTPROV hProv = 0;
58
59                 /* Get handle to user default provider */
60                 if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
61                    return -1;
62                 }
63
64                 /* Generate random initialization vector */
65                 if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) {
66                    return -1;
67                 }
68
69                 /* Release provider handle */
70                 if(hProv != 0) CryptReleaseContext(hProv, 0);
71
72                 return 0;
73         }
74 #else
75         {
76                 /* based upon Phil Karn's "practical randomness" idea
77                  * but implementation 100% OpenLDAP.  So don't blame Phil. */
78                 /* worse case is this is a MD5 hash of a counter, if
79                  *      MD5 is a strong cryptographic hash, this should
80                  *      be fairly resistant to attack
81                  */
82
83                 /*
84                  * the caller may need to provide external synchronization OR
85                  * provide entropy (in buf) to ensure quality results as
86                  * access to this counter may not be atomic.
87                  */
88                 static int counter = 0;
89                 int n;
90
91                 struct rdata_s {
92                         int counter;
93
94                         char *buf;
95                         struct rdata_s *stack;
96
97                         pid_t   pid;
98
99 #ifdef HAVE_GETTIMEOFDAY
100                         struct timeval tv;
101 #else
102                         time_t  time;
103 #endif
104
105                         unsigned long   junk;   /* purposely not initialized */
106                 } rdata;
107
108                 /* make sure rdata differs for each process */
109                 rdata.pid = getpid();
110
111                 /* make sure rdata differs for each program */
112                 rdata.buf = buf;
113                 rdata.stack = &rdata;
114
115                 for( n = 0; n < nbytes; n += 16 ) {
116                         struct lutil_MD5Context ctx;
117                         char digest[16];
118
119                         /* poor resolution */
120 #ifdef HAVE_GETTIMEOFDAY
121                         (void) gettimeofday( &rdata.tv, NULL );
122 #else
123                         (void) time( &rdata.time );
124 #endif
125
126                         /* make sure rdata differs */
127                         rdata.counter = ++counter;
128                         rdata.pid++;
129                         rdata.junk++;
130
131                         lutil_MD5Init( &ctx );
132                         lutil_MD5Update( &ctx, (char *) &rdata, sizeof( rdata ) );
133
134                         /* allow caller to provided additional entropy */
135                         lutil_MD5Update( &ctx, (char *) &buf, nbytes );
136
137                         lutil_MD5Final( digest, &ctx );
138
139                         memcpy( &buf[n], digest,
140                                 nbytes - n >= 16 ? 16 : nbytes - n );
141                 }
142
143                 return 0;
144         }
145 #endif
146         return -1;
147 }