summaryrefslogtreecommitdiffhomepage
path: root/libtomcrypt/src/prngs/fortuna.c
diff options
context:
space:
mode:
Diffstat (limited to 'libtomcrypt/src/prngs/fortuna.c')
-rw-r--r--libtomcrypt/src/prngs/fortuna.c181
1 files changed, 102 insertions, 79 deletions
diff --git a/libtomcrypt/src/prngs/fortuna.c b/libtomcrypt/src/prngs/fortuna.c
index d262a0b..7b1ecb6 100644
--- a/libtomcrypt/src/prngs/fortuna.c
+++ b/libtomcrypt/src/prngs/fortuna.c
@@ -5,8 +5,6 @@
*
* The library is free for all purposes without any express
* guarantee it works.
- *
- * Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*/
#include "tomcrypt.h"
@@ -14,14 +12,14 @@
@file fortuna.c
Fortuna PRNG, Tom St Denis
*/
-
-/* Implementation of Fortuna by Tom St Denis
+
+/* Implementation of Fortuna by Tom St Denis
We deviate slightly here for reasons of simplicity [and to fit in the API]. First all "sources"
-in the AddEntropy function are fixed to 0. Second since no reliable timer is provided
+in the AddEntropy function are fixed to 0. Second since no reliable timer is provided
we reseed automatically when len(pool0) >= 64 or every LTC_FORTUNA_WD calls to the read function */
-#ifdef LTC_FORTUNA
+#ifdef LTC_FORTUNA
/* requries LTC_SHA256 and AES */
#if !(defined(LTC_RIJNDAEL) && defined(LTC_SHA256))
@@ -38,7 +36,8 @@ we reseed automatically when len(pool0) >= 64 or every LTC_FORTUNA_WD calls to t
#endif
const struct ltc_prng_descriptor fortuna_desc = {
- "fortuna", 1024,
+ "fortuna",
+ (32 * LTC_FORTUNA_POOLS), /* default: 1024 */
&fortuna_start,
&fortuna_add_entropy,
&fortuna_ready,
@@ -50,7 +49,7 @@ const struct ltc_prng_descriptor fortuna_desc = {
};
/* update the IV */
-static void fortuna_update_iv(prng_state *prng)
+static void _fortuna_update_iv(prng_state *prng)
{
int x;
unsigned char *IV;
@@ -63,7 +62,7 @@ static void fortuna_update_iv(prng_state *prng)
}
/* reseed the PRNG */
-static int fortuna_reseed(prng_state *prng)
+static int _fortuna_reseed(prng_state *prng)
{
unsigned char tmp[MAXBLOCKSIZE];
hash_state md;
@@ -79,11 +78,11 @@ static int fortuna_reseed(prng_state *prng)
}
for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
- if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) {
+ if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) {
/* terminate this hash */
if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
sha256_done(&md, tmp);
- return err;
+ return err;
}
/* add it to the string */
if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) {
@@ -102,12 +101,12 @@ static int fortuna_reseed(prng_state *prng)
/* finish key */
if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
- return err;
+ return err;
}
if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
return err;
}
- fortuna_update_iv(prng);
+ _fortuna_update_iv(prng);
/* reset pool len */
prng->fortuna.pool0_len = 0;
@@ -126,14 +125,15 @@ static int fortuna_reseed(prng_state *prng)
Start the PRNG
@param prng [out] The PRNG state to initialize
@return CRYPT_OK if successful
-*/
+*/
int fortuna_start(prng_state *prng)
{
int err, x, y;
unsigned char tmp[MAXBLOCKSIZE];
LTC_ARGCHK(prng != NULL);
-
+ prng->ready = 0;
+
/* initialize the pools */
for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
if ((err = sha256_init(&prng->fortuna.pool[x])) != CRYPT_OK) {
@@ -155,9 +155,9 @@ int fortuna_start(prng_state *prng)
return err;
}
zeromem(prng->fortuna.IV, 16);
-
- LTC_MUTEX_INIT(&prng->fortuna.prng_lock)
-
+
+ LTC_MUTEX_INIT(&prng->lock)
+
return CRYPT_OK;
}
@@ -167,33 +167,31 @@ int fortuna_start(prng_state *prng)
@param inlen Length of the data to add
@param prng PRNG state to update
@return CRYPT_OK if successful
-*/
+*/
int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
{
unsigned char tmp[2];
int err;
- LTC_ARGCHK(in != NULL);
LTC_ARGCHK(prng != NULL);
-
- LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(inlen > 0);
/* ensure inlen <= 32 */
if (inlen > 32) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return CRYPT_INVALID_ARG;
+ inlen = 32;
}
/* add s || length(in) || in to pool[pool_idx] */
tmp[0] = 0;
tmp[1] = (unsigned char)inlen;
+
+ LTC_MUTEX_LOCK(&prng->lock);
if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return err;
+ goto LBL_UNLOCK;
}
if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], in, inlen)) != CRYPT_OK) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return err;
+ goto LBL_UNLOCK;
}
if (prng->fortuna.pool_idx == 0) {
prng->fortuna.pool0_len += inlen;
@@ -201,19 +199,29 @@ int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state
if (++(prng->fortuna.pool_idx) == LTC_FORTUNA_POOLS) {
prng->fortuna.pool_idx = 0;
}
+ err = CRYPT_OK; /* success */
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return CRYPT_OK;
+LBL_UNLOCK:
+ LTC_MUTEX_UNLOCK(&prng->lock);
+ return err;
}
/**
Make the PRNG ready to read from
@param prng The PRNG to make active
@return CRYPT_OK if successful
-*/
+*/
int fortuna_ready(prng_state *prng)
{
- return fortuna_reseed(prng);
+ int err;
+ LTC_ARGCHK(prng != NULL);
+
+ LTC_MUTEX_LOCK(&prng->lock);
+ err = _fortuna_reseed(prng);
+ prng->ready = (err == CRYPT_OK) ? 1 : 0;
+
+ LTC_MUTEX_UNLOCK(&prng->lock);
+ return err;
}
/**
@@ -222,23 +230,24 @@ int fortuna_ready(prng_state *prng)
@param outlen Length of output
@param prng The active PRNG to read from
@return Number of octets read
-*/
+*/
unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng)
{
unsigned char tmp[16];
- int err;
- unsigned long tlen;
+ unsigned long tlen = 0;
- LTC_ARGCHK(out != NULL);
- LTC_ARGCHK(prng != NULL);
+ if (outlen == 0 || prng == NULL || out == NULL) return 0;
+
+ LTC_MUTEX_LOCK(&prng->lock);
- LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
+ if (!prng->ready) {
+ goto LBL_UNLOCK;
+ }
/* do we have to reseed? */
if (++prng->fortuna.wd == LTC_FORTUNA_WD || prng->fortuna.pool0_len >= 64) {
- if ((err = fortuna_reseed(prng)) != CRYPT_OK) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return 0;
+ if (_fortuna_reseed(prng) != CRYPT_OK) {
+ goto LBL_UNLOCK;
}
}
@@ -251,59 +260,66 @@ unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state
rijndael_ecb_encrypt(prng->fortuna.IV, out, &prng->fortuna.skey);
out += 16;
outlen -= 16;
- fortuna_update_iv(prng);
+ _fortuna_update_iv(prng);
}
/* left over bytes? */
if (outlen > 0) {
rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
XMEMCPY(out, tmp, outlen);
- fortuna_update_iv(prng);
+ _fortuna_update_iv(prng);
}
-
+
/* generate new key */
- rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K , &prng->fortuna.skey); fortuna_update_iv(prng);
- rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K+16, &prng->fortuna.skey); fortuna_update_iv(prng);
- if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return 0;
+ rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K , &prng->fortuna.skey);
+ _fortuna_update_iv(prng);
+
+ rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K+16, &prng->fortuna.skey);
+ _fortuna_update_iv(prng);
+
+ if (rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey) != CRYPT_OK) {
+ tlen = 0;
}
+LBL_UNLOCK:
#ifdef LTC_CLEAN_STACK
zeromem(tmp, sizeof(tmp));
#endif
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
+ LTC_MUTEX_UNLOCK(&prng->lock);
return tlen;
-}
+}
/**
Terminate the PRNG
@param prng The PRNG to terminate
@return CRYPT_OK if successful
-*/
+*/
int fortuna_done(prng_state *prng)
{
int err, x;
unsigned char tmp[32];
LTC_ARGCHK(prng != NULL);
- LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
+
+ LTC_MUTEX_LOCK(&prng->lock);
+ prng->ready = 0;
/* terminate all the hashes */
for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return err;
+ goto LBL_UNLOCK;
}
}
/* call cipher done when we invent one ;-) */
+ err = CRYPT_OK; /* success */
+LBL_UNLOCK:
#ifdef LTC_CLEAN_STACK
zeromem(tmp, sizeof(tmp));
#endif
-
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return CRYPT_OK;
+ LTC_MUTEX_UNLOCK(&prng->lock);
+ LTC_MUTEX_DESTROY(&prng->lock);
+ return err;
}
/**
@@ -312,34 +328,40 @@ int fortuna_done(prng_state *prng)
@param outlen [in/out] Max size and resulting size of the state
@param prng The PRNG to export
@return CRYPT_OK if successful
-*/
+*/
int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
{
int x, err;
hash_state *md;
+ unsigned long len = fortuna_desc.export_size;
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(prng != NULL);
- LTC_MUTEX_LOCK(&prng->fortuna.prng_lock);
+ LTC_MUTEX_LOCK(&prng->lock);
+
+ if (!prng->ready) {
+ err = CRYPT_ERROR;
+ goto LBL_UNLOCK;
+ }
/* we'll write bytes for s&g's */
- if (*outlen < 32*LTC_FORTUNA_POOLS) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- *outlen = 32*LTC_FORTUNA_POOLS;
- return CRYPT_BUFFER_OVERFLOW;
+ if (*outlen < len) {
+ *outlen = len;
+ err = CRYPT_BUFFER_OVERFLOW;
+ goto LBL_UNLOCK;
}
md = XMALLOC(sizeof(hash_state));
if (md == NULL) {
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
- return CRYPT_MEM;
+ err = CRYPT_MEM;
+ goto LBL_UNLOCK;
}
- /* to emit the state we copy each pool, terminate it then hash it again so
- * an attacker who sees the state can't determine the current state of the PRNG
- */
+ /* to emit the state we copy each pool, terminate it then hash it again so
+ * an attacker who sees the state can't determine the current state of the PRNG
+ */
for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
/* copy the PRNG */
XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md));
@@ -360,7 +382,7 @@ int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
goto LBL_ERR;
}
}
- *outlen = 32*LTC_FORTUNA_POOLS;
+ *outlen = len;
err = CRYPT_OK;
LBL_ERR:
@@ -368,17 +390,18 @@ LBL_ERR:
zeromem(md, sizeof(*md));
#endif
XFREE(md);
- LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock);
+LBL_UNLOCK:
+ LTC_MUTEX_UNLOCK(&prng->lock);
return err;
}
-
+
/**
Import a PRNG state
@param in The PRNG state
@param inlen Size of the state
@param prng The PRNG to import
@return CRYPT_OK if successful
-*/
+*/
int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
{
int err, x;
@@ -386,7 +409,7 @@ int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prn
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(prng != NULL);
- if (inlen != 32*LTC_FORTUNA_POOLS) {
+ if (inlen < (unsigned long)fortuna_desc.export_size) {
return CRYPT_INVALID_ARG;
}
@@ -398,13 +421,13 @@ int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prn
return err;
}
}
- return err;
+ return CRYPT_OK;
}
/**
PRNG self-test
@return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
-*/
+*/
int fortuna_test(void)
{
#ifndef LTC_TEST
@@ -422,6 +445,6 @@ int fortuna_test(void)
#endif
-/* $Source$ */
-/* $Revision$ */
-/* $Date$ */
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */