home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / liblutil / entropy.c < prev    next >
C/C++ Source or Header  |  2000-10-31  |  3KB  |  153 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/liblutil/entropy.c,v 1.15.2.4 2000/10/30 16:40:10 kurt Exp $ */
  2. /*
  3.  * Copyright 1998-2000 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. #include <ac/unistd.h>
  12.  
  13. #ifdef HAVE_WINCRYPT_H
  14. #include <wincrypt.h>
  15. #endif
  16. #ifdef HAVE_PROCESS_H
  17. #include <process.h>
  18. #endif
  19.  
  20. #include <fcntl.h>
  21.  
  22. #include <lutil.h>
  23. #include <lutil_md5.h>
  24.  
  25. /*
  26.  * lutil_entropy() provides nbytes of entropy in buf.
  27.  * Quality offerred is suitable for one-time uses, such as "once" keys.
  28.  * Values may not be suitable for multi-time uses.
  29.  *
  30.  * Note:  Callers are encouraged to provide additional bytes of
  31.  * of entropy in the buf argument.  This information is used in
  32.  * fallback mode to improve the quality of bytes returned.
  33.  *
  34.  * This routinue should be extended to support additional sources
  35.  * of entropy.
  36.  */
  37. int lutil_entropy( unsigned char *buf, ber_len_t nbytes )
  38. {
  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.         ber_len_t n;
  95.  
  96.         struct rdata_s {
  97.             int counter;
  98.  
  99.             unsigned 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, (unsigned char *) &rdata, sizeof( rdata ) );
  138.  
  139.             /* allow caller to provided additional entropy */
  140.             lutil_MD5Update( &ctx, buf, nbytes );
  141.  
  142.             lutil_MD5Final( digest, &ctx );
  143.  
  144.             AC_MEMCPY( &buf[n], digest,
  145.                 nbytes - n >= 16 ? 16 : nbytes - n );
  146.         }
  147.  
  148.         return 0;
  149.     }
  150. #endif
  151.     return -1;
  152. }
  153.