]> git.sur5r.net Git - openldap/blob - libraries/liblutil/entropy.c
Add a fallback based upon Phil Karn's "practical randomness" idea.
[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 resisant to attack
48                  */
49                 static int initialized = 0;
50                 int n;
51
52                 struct {
53                         pid_t   pid;
54
55 #ifdef HAVE_GETTIMEOFDAY
56                         struct timeval *tv;
57 #else
58                         time_t  time;
59 #endif
60                         unsigned long   junk;
61                 } rdata;
62
63                 if( !initialized ) {
64                         initialized++;
65
66                         rdata.pid = getpid();
67                 }
68                 
69                 for( n = 0; n < nbytes; n += 16 ) {
70                         struct lutil_MD5Context ctx;
71                         char digest[16];
72
73 #ifdef HAVE_GETTIMEOFDAY
74                         (void) gettimeofday( &rdata.tv, sizeof( rdata.tv ) );
75 #else
76                         (void) time( &rdata.time );
77 #endif
78
79                         rdata.pid++;
80                         rdata.junk++;
81
82                         lutil_MD5Init( &ctx );
83                         lutil_MD5Update( &ctx, (char *) &rdata, sizeof( rdata ) );
84                         lutil_MD5Final( digest, &ctx );
85
86                         memcpy( &buf[n], digest,
87                                 nbytes - n > 16 ? 16 : nbytes - n );
88                 }
89
90                 return 0;
91         }
92 #endif
93         return -1;
94 }