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