/*
-Copyright (c) 2006, John Hurst
+Copyright (c) 2006-2009, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#include <assert.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
+#include <openssl/bn.h>
using namespace Kumu;
#ifdef KM_WIN32
-
-// make up a byte by sampling the perf counter LSB
-static byte_t get_perf_byte(byte_t carry)
-{
- LARGE_INTEGER ticks;
- byte_t sha_buf[20];
- SHA_CTX SHA;
- SHA1_Init(&SHA);
- SHA1_Update(&SHA, &carry, sizeof(byte_t));
-
- for ( int i = 0; i < 128; i++ )
- {
- QueryPerformanceCounter(&ticks);
- SHA1_Update(&SHA, &ticks.LowPart, sizeof(ticks.LowPart));
- }
-
- SHA1_Final(sha_buf, &SHA);
-
- fprintf(stderr, "0x%02x ", sha_buf[0]);
- return sha_buf[0];
-}
-
+# include <wincrypt.h>
#else // KM_WIN32
-
-#include <KM_fileio.h>
+# include <KM_fileio.h>
const char* DEV_URANDOM = "/dev/urandom";
-
#endif // KM_WIN32
AutoMutex Lock(m_Lock);
#ifdef KM_WIN32
- for ( ui32_t i = 0; i < RNG_KEY_SIZE; i++ )
- {
- byte_t carry = ( i == 0 ) ? 0xa3 : rng_key[i-1];
- rng_key[i] = get_perf_byte(carry);
- }
+ HCRYPTPROV hProvider = 0;
+ CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ CryptGenRandom(hProvider, RNG_KEY_SIZE, rng_key);
#else // KM_WIN32
// on POSIX systems we simply read some seed from /dev/urandom
FileReader URandom;
{
byte_t tmp[RNG_BLOCK_SIZE];
AES_encrypt(m_ctr_buf, tmp, &m_Context);
- *(ui32_t*)(m_ctr_buf + 12) += 1;
- memcpy(buf, tmp, len - gen_count);
+ memcpy(buf + gen_count, tmp, len - gen_count);
}
}
};
//------------------------------------------------------------------------------------------
//
-// public interface
+// Fortuna public interface
Kumu::FortunaRNG::FortunaRNG()
{
{
assert(buf);
assert(s_RNG);
+ const byte_t* front_of_buffer = buf;
while ( len )
{
s_RNG->set_key(rng_key);
}
- return buf;
+ return front_of_buffer;
}
//
return Buffer.Data();
}
+//------------------------------------------------------------------------------------------
+
+//
+// FIPS 186-2 Sec. 3.1 as modified by Change 1, section entitled "General Purpose Random Number Generation"
+void
+Kumu::Gen_FIPS_186_Value(const byte_t* key, ui32_t key_size, byte_t* out_buf, ui32_t out_buf_len)
+{
+ byte_t sha_buf[SHA_DIGEST_LENGTH];
+ ui32_t const xkey_len = 64; // 512/8
+ byte_t xkey[xkey_len];
+ BN_CTX* ctx1 = BN_CTX_new(); // used by BN_* functions
+ assert(ctx1);
+
+ if ( key_size > xkey_len )
+ DefaultLogSink().Warn("Key too large for FIPS 186 seed, truncating to 64 bytes.\n");
+
+ // init key
+ memset(xkey, 0, xkey_len);
+ memcpy(xkey, key, xmin<ui32_t>(key_size, xkey_len));
+
+ if ( key_size < SHA_DIGEST_LENGTH )
+ key_size = SHA_DIGEST_LENGTH; // pad short key ( b < 160 )
+
+ // create the 2^b constant
+ BIGNUM *c_2powb = BN_new();
+ BIGNUM * c_2 = BN_new();
+ BIGNUM * c_b = BN_new();
+ assert(c_2powb);
+ assert(c_2);
+ assert(c_b);
+
+ BN_set_word(c_2, 2);
+ BN_set_word(c_b, key_size * 8);
+ BN_exp(c_2powb, c_2, c_b, ctx1);
+
+ for (;;)
+ {
+ SHA_CTX SHA;
+
+ // step c -- x = G(t,xkey)
+ SHA1_Init(&SHA); // set t
+ SHA1_Update(&SHA, xkey, xkey_len);
+
+ ui32_t* buf_p = (ui32_t*)sha_buf;
+ *buf_p++ = KM_i32_BE(SHA.h0);
+ *buf_p++ = KM_i32_BE(SHA.h1);
+ *buf_p++ = KM_i32_BE(SHA.h2);
+ *buf_p++ = KM_i32_BE(SHA.h3);
+ *buf_p++ = KM_i32_BE(SHA.h4);
+ memcpy(out_buf, sha_buf, xmin<ui32_t>(out_buf_len, SHA_DIGEST_LENGTH));
+
+ if ( out_buf_len <= SHA_DIGEST_LENGTH )
+ break;
+
+ out_buf_len -= SHA_DIGEST_LENGTH;
+ out_buf += SHA_DIGEST_LENGTH;
+
+ // step d -- XKEY = (1 + XKEY + x) mod 2^b
+ BIGNUM *bn_tmp = BN_new();
+ BIGNUM *bn_xkey = BN_new();
+ BIGNUM *bn_x_n = BN_new();
+ assert(bn_tmp);
+ assert(bn_xkey);
+ assert(bn_x_n);
+
+ BN_bin2bn(xkey, key_size, bn_xkey);
+ BN_bin2bn(sha_buf, SHA_DIGEST_LENGTH, bn_x_n);
+ BN_add_word(bn_xkey, 1); // xkey += 1
+ BN_add(bn_tmp, bn_xkey, bn_x_n); // xkey += x
+ BN_mod(bn_xkey, bn_tmp, c_2powb, ctx1); // xkey = xkey mod (2^b)
+
+ memset(xkey, 0, xkey_len);
+ ui32_t bn_buf_len = BN_num_bytes(bn_xkey);
+ ui32_t idx = ( bn_buf_len < key_size ) ? key_size - bn_buf_len : 0;
+ BN_bn2bin(bn_xkey, &xkey[idx]);
+ BN_free(bn_tmp);
+ BN_free(bn_xkey);
+ BN_free(bn_x_n);
+ }
+
+ BN_free(c_2powb);
+ BN_free(c_2);
+ BN_free(c_b);
+ BN_CTX_free(ctx1);
+}
//
// end KM_prng.cpp