Home | History | Annotate | Download | only in prngs
      1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
      2  *
      3  * LibTomCrypt is a library that provides various cryptographic
      4  * algorithms in a highly modular and flexible manner.
      5  *
      6  * The library is free for all purposes without any express
      7  * guarantee it works.
      8  *
      9  * Tom St Denis, tomstdenis (at) gmail.com, http://libtomcrypt.com
     10  */
     11 #include "tomcrypt.h"
     12 
     13 /**
     14    @file rng_get_bytes.c
     15    portable way to get secure random bits to feed a PRNG (Tom St Denis)
     16 */
     17 
     18 #ifdef DEVRANDOM
     19 /* on *NIX read /dev/random */
     20 static unsigned long rng_nix(unsigned char *buf, unsigned long len,
     21                              void (*callback)(void))
     22 {
     23 #ifdef LTC_NO_FILE
     24     return 0;
     25 #else
     26     FILE *f;
     27     unsigned long x;
     28 #ifdef TRY_URANDOM_FIRST
     29     f = fopen("/dev/urandom", "rb");
     30     if (f == NULL)
     31 #endif /* TRY_URANDOM_FIRST */
     32        f = fopen("/dev/random", "rb");
     33 
     34     if (f == NULL) {
     35        return 0;
     36     }
     37 
     38     /* disable buffering */
     39     if (setvbuf(f, NULL, _IONBF, 0) != 0) {
     40        fclose(f);
     41        return 0;
     42     }
     43 
     44     x = (unsigned long)fread(buf, 1, (size_t)len, f);
     45     fclose(f);
     46     return x;
     47 #endif /* LTC_NO_FILE */
     48 }
     49 
     50 #endif /* DEVRANDOM */
     51 
     52 /* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */
     53 #if defined(CLOCKS_PER_SEC) && !defined(WINCE)
     54 
     55 #define ANSI_RNG
     56 
     57 static unsigned long rng_ansic(unsigned char *buf, unsigned long len,
     58                                void (*callback)(void))
     59 {
     60    clock_t t1;
     61    int l, acc, bits, a, b;
     62 
     63    if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) {
     64       return 0;
     65    }
     66 
     67    l = len;
     68    bits = 8;
     69    acc  = a = b = 0;
     70    while (len--) {
     71        if (callback != NULL) callback();
     72        while (bits--) {
     73           do {
     74              t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1;
     75              t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1;
     76           } while (a == b);
     77           acc = (acc << 1) | a;
     78        }
     79        *buf++ = acc;
     80        acc  = 0;
     81        bits = 8;
     82    }
     83    acc = bits = a = b = 0;
     84    return l;
     85 }
     86 
     87 #endif
     88 
     89 /* Try the Microsoft CSP */
     90 #if defined(WIN32) || defined(WINCE)
     91 #define _WIN32_WINNT 0x0400
     92 #ifdef WINCE
     93    #define UNDER_CE
     94    #define ARM
     95 #endif
     96 #include <windows.h>
     97 #include <wincrypt.h>
     98 
     99 static unsigned long rng_win32(unsigned char *buf, unsigned long len,
    100                                void (*callback)(void))
    101 {
    102    HCRYPTPROV hProv = 0;
    103    if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
    104                             (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
    105        !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
    106                             CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
    107       return 0;
    108 
    109    if (CryptGenRandom(hProv, len, buf) == TRUE) {
    110       CryptReleaseContext(hProv, 0);
    111       return len;
    112    } else {
    113       CryptReleaseContext(hProv, 0);
    114       return 0;
    115    }
    116 }
    117 
    118 #endif /* WIN32 */
    119 
    120 /**
    121   Read the system RNG
    122   @param out       Destination
    123   @param outlen    Length desired (octets)
    124   @param callback  Pointer to void function to act as "callback" when RNG is slow.  This can be NULL
    125   @return Number of octets read
    126 */
    127 unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen,
    128                             void (*callback)(void))
    129 {
    130    unsigned long x;
    131 
    132    LTC_ARGCHK(out != NULL);
    133 
    134 #if defined(DEVRANDOM)
    135    x = rng_nix(out, outlen, callback);   if (x != 0) { return x; }
    136 #endif
    137 #ifdef WIN32
    138    x = rng_win32(out, outlen, callback); if (x != 0) { return x; }
    139 #endif
    140 #ifdef ANSI_RNG
    141    x = rng_ansic(out, outlen, callback); if (x != 0) { return x; }
    142 #endif
    143    return 0;
    144 }
    145 
    146 /* $Source: /cvs/libtom/libtomcrypt/src/prngs/rng_get_bytes.c,v $ */
    147 /* $Revision: 1.5 $ */
    148 /* $Date: 2006/12/06 02:01:29 $ */
    149