]> git.sur5r.net Git - openldap/blob - libraries/liblutil/entropy.c
4a15a789d462e429c41ee294ab07d5380a47ecdc
[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 <fcntl.h>
10
11 #include <lutil.h>
12 #include <lutil_md5.h>
13
14 /*
15  * lutil_entropy() provides nbytes of entropy in buf.
16  * Quality offerred is suitable for one-time uses, such as "once" keys.
17  */
18 int lutil_entropy( char *buf, int nbytes )
19 {
20         if( nbytes < 0 ) return -1;
21         if( nbytes == 0 ) return 0;
22
23 #undef URANDOM_DEVICE
24 #ifdef URANDOM_DEVICE
25         /* Linux and *BSD offer a urandom device */
26         {
27                 int rc, fd;
28
29                 fd = open( URANDOM_DEVICE, O_RDONLY );
30
31                 if( fd < 0 ) return -1;
32
33                 rc = read( fd, buf, nbytes );
34                 close(fd);
35
36                 /* should return nbytes */
37                 if( rc < nbytes ) return -1;
38
39                 return 0;
40         }
41 #else
42         {
43                 /* based upon Phil Karn's "practical randomness" idea
44                  * but implementation 100% OpenLDAP.  So don't blame Phil. */
45                 /* worse case is this is a MD5 hash of a counter, if
46                  *      MD5 is a strong cryptographic hash, this should
47                  *      be fairly resistant to attack
48                  */
49                 static int counter = 0;
50                 int n;
51
52                 struct rdata_s {
53                         int counter;
54
55                         char *buf;
56                         struct rdata_s *stack;
57
58                         pid_t   pid;
59
60 #ifdef HAVE_GETTIMEOFDAY
61                         struct timeval *tv;
62 #else
63                         time_t  time;
64 #endif
65                         unsigned long   junk;
66                 } rdata;
67
68                 /* make sure rdata differs for each process */
69                 rdata.pid = getpid();
70
71                 /* make sure rdata differs for each program */
72                 rdata.buf = buf;
73                 rdata.stack = &rdata;
74
75                 for( n = 0; n < nbytes; n += 16 ) {
76                         struct lutil_MD5Context ctx;
77                         char digest[16];
78
79                         /* hopefully has good resolution */
80 #ifdef HAVE_GETTIMEOFDAY
81                         (void) gettimeofday( &rdata.tv, sizeof( rdata.tv ) );
82 #else
83                         (void) time( &rdata.time );
84 #endif
85
86                         /* make sure rdata differs */
87                         rdata.counter = ++counter;
88                         rdata.pid++;
89                         rdata.junk++;
90
91                         lutil_MD5Init( &ctx );
92                         lutil_MD5Update( &ctx, (char *) &rdata, sizeof( rdata ) );
93                         lutil_MD5Final( digest, &ctx );
94
95                         memcpy( &buf[n], digest,
96                                 nbytes - n > 16 ? 16 : nbytes - n );
97                 }
98
99                 return 0;
100         }
101 #endif
102         return -1;
103 }