/*
-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;
//------------------------------------------------------------------------------------------
//
-// 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