123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /* portable way to get secure random bits to feed a PRNG */
- #include <fcntl.h>
- #include <unistd.h>
- #include "mycrypt.h"
- #ifdef DEVRANDOM
- /* on *NIX read /dev/random */
- static unsigned long rng_nix(unsigned char *buf, unsigned long len,
- void (*callback)(void))
- {
- #ifdef NO_FILE
- return 0;
- #else
- int src;
- unsigned long x;
- #ifdef TRY_URANDOM_FIRST
- src = open("/dev/urandom", O_RDONLY);
- if (src == -1)
- #endif /* TRY_URANDOM_FIRST */
- src = open("/dev/random", O_RDONLY);
- if (src == -1) {
- return 0;
- }
-
- x = (unsigned long)read(src, buf, (size_t)len);
- close(src);
- return x;
- #endif /* NO_FILE */
- }
- #endif /* DEVRANDOM */
- #ifdef SONY_PS2
- #include <eetypes.h>
- #include <eeregs.h>
- #define min(a,b) ((a) < (b) ? (a) : (b))
- // Very simple/stupid MD5-based RNG that samples "entropy" from various PS2 control registers
- static unsigned long rng_ps2(unsigned char *buf, unsigned long len,
- void (*callback)(void))
- {
- static unsigned long lastx[2] = { 0xaab7cb4b2fd3b2b9, 0xcec58aff72afe49f }; // md5sum of bits.c
- unsigned long j;
- unsigned int samples[10]; // number of sample data sources
- int l;
- hash_state md;
- for (j = 0; j < len; j += sizeof(lastx)) {
- md5_init(&md);
- samples[0] = *T2_COUNT;
- samples[1] = *T3_COUNT;
- samples[2] = *IPU_TOP;
- samples[3] = *GIF_TAG0;
- samples[4] = *GIF_TAG1;
- samples[5] = *GIF_TAG2;
- samples[6] = *VIF1_CODE;
- samples[7] = *VIF0_CODE;
- samples[8] = *D0_MADR;
- samples[9] = *D1_MADR;
- md5_process(&md, (unsigned char *)(&samples[0]), sizeof(samples));
- // include previous round
- md5_process(&md, (unsigned char *)(&lastx[0]), sizeof(lastx));
- md5_done(&md, (unsigned char *)(&lastx[0]));
- l = min(sizeof(lastx), len-j);
- memcpy(buf+j, &lastx[0], l); //min(sizeof(lastx), len-j));
- }
- return len;
- }
- #endif /* SONY_PS2 */
- /* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */
- #if !defined(SONY_PS2) && defined(CLOCKS_PER_SEC)
- #define ANSI_RNG
- static unsigned long rng_ansic(unsigned char *buf, unsigned long len,
- void (*callback)(void))
- {
- 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--) {
- if (callback != NULL) callback();
- 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 */
- #ifdef WIN32
- #define _WIN32_WINNT 0x0400
- #include <windows.h>
- #include <wincrypt.h>
- static unsigned long rng_win32(unsigned char *buf, unsigned long len,
- void (*callback)(void))
- {
- 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 /* WIN32 */
- unsigned long rng_get_bytes(unsigned char *buf, unsigned long len,
- void (*callback)(void))
- {
- unsigned long x;
- _ARGCHK(buf != NULL);
- #ifdef SONY_PS2
- x = rng_ps2(buf, len, callback); if (x != 0) { return x; }
- #elif defined(DEVRANDOM)
- x = rng_nix(buf, len, callback); if (x != 0) { return x; }
- #endif
- #ifdef WIN32
- x = rng_win32(buf, len, callback); if (x != 0) { return x; }
- #endif
- #ifdef ANSI_RNG
- x = rng_ansic(buf, len, callback); if (x != 0) { return x; }
- #endif
- return 0;
- }
- int rng_make_prng(int bits, int wprng, prng_state *prng,
- void (*callback)(void))
- {
- unsigned char buf[256];
- int err;
-
- _ARGCHK(prng != NULL);
- /* check parameter */
- if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
- return err;
- }
- if (bits < 64 || bits > 1024) {
- return CRYPT_INVALID_PRNGSIZE;
- }
- if ((err = prng_descriptor[wprng].start(prng)) != CRYPT_OK) {
- return err;
- }
- bits = ((bits/8)+((bits&7)!=0?1:0)) * 2;
- if (rng_get_bytes(buf, (unsigned long)bits, callback) != (unsigned long)bits) {
- return CRYPT_ERROR_READPRNG;
- }
- if ((err = prng_descriptor[wprng].add_entropy(buf, (unsigned long)bits, prng)) != CRYPT_OK) {
- return err;
- }
- if ((err = prng_descriptor[wprng].ready(prng)) != CRYPT_OK) {
- return err;
- }
- #ifdef CLEAN_STACK
- zeromem(buf, sizeof(buf));
- #endif
- return CRYPT_OK;
- }
|