/* * Adaped from libtomcrypt by Tom St Denis. * * by Nathan Wagner, and released into the public domain */ #include #define LTC_ARGCHK(x) #define TRY_URANDOM_FIRST 1 #ifndef WIN32 #define LTC_DEVRANDOM 1 #endif #ifdef LTC_DEVRANDOM /* on *NIX read /dev/random */ static unsigned long rng_nix(unsigned char *buf, unsigned long len) { #ifdef LTC_NO_FILE return 0; #else FILE *f; unsigned long x; #ifdef TRY_URANDOM_FIRST f = fopen("/dev/urandom", "rb"); if (f == NULL) #endif f = fopen("/dev/random", "rb"); if (f == NULL) { return 0; } /* disable buffering */ if (setvbuf(f, NULL, _IONBF, 0) != 0) { fclose(f); return 0; } x = (unsigned long) fread(buf, 1, (size_t) len, f); fclose(f); return x; #endif } #endif /* TODO remove this. It's too slow really (I think) */ /* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */ #if defined(CLOCKS_PER_SEC) && !defined(WINCE) #define ANSI_RNG static unsigned long rng_ansic(unsigned char *buf, unsigned long len) { clock_t t1; int l, acc, bits, a, b; if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) { return 0; } l = len; bits = 8; acc = a = b = 0; while (len--) { while (bits--) { do { t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1; t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1; } while (a == b); acc = (acc << 1) | a; } *buf++ = acc; acc = 0; bits = 8; } acc = bits = a = b = 0; return l; } #endif /* Try the Microsoft CSP */ #if defined(WIN32) || defined(WINCE) #warning using WIN32 #define _WIN32_WINNT 0x0400 #ifdef WINCE #define UNDER_CE #define ARM #endif #include #include static unsigned long rng_win32(unsigned char *buf, unsigned long len) { HCRYPTPROV hProv = 0; if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && !CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) return 0; if (CryptGenRandom(hProv, len, buf) == TRUE) { CryptReleaseContext(hProv, 0); return len; } else { CryptReleaseContext(hProv, 0); return 0; } } #endif unsigned long pd_uuid_rng_get_bytes(unsigned char *out, unsigned long outlen) { unsigned long x; LTC_ARGCHK(out != NULL); #if defined(LTC_DEVRANDOM) x = rng_nix(out, outlen); if (x != 0) { return x; } #endif #ifdef WIN32 x = rng_win32(out, outlen); if (x != 0) { return x; } #endif #ifdef ANSI_RNG x = rng_ansic(out, outlen); if (x != 0) { return x; } #endif return 0; }