diff libtomcrypt/src/prngs/fortuna.c @ 1471:6dba84798cd5

Update to libtomcrypt 1.18.1, merged with Dropbear changes
author Matt Johnston <matt@ucc.asn.au>
date Fri, 09 Feb 2018 21:44:05 +0800
parents f849a5ca2efc
children e9dba7abd939
line wrap: on
line diff
--- a/libtomcrypt/src/prngs/fortuna.c	Thu Feb 08 23:11:40 2018 +0800
+++ b/libtomcrypt/src/prngs/fortuna.c	Fri Feb 09 21:44:05 2018 +0800
@@ -5,8 +5,6 @@
  *
  * The library is free for all purposes without any express
  * guarantee it works.
- *
- * Tom St Denis, [email protected], 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 @@
 #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 @@
 };
 
 /* 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 @@
 }
 
 /* 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 @@
    }
 
    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 @@
 
    /* 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 @@
   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 @@
       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 @@
   @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 @@
    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 @@
   @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;
+
+   if (outlen == 0 || prng == NULL || out == NULL) return 0;
 
-   LTC_ARGCHK(out  != NULL);
-   LTC_ARGCHK(prng != NULL);
+   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 @@
       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);
-   }
-       
-   /* 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;
+      _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 (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 @@
   @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 @@
          goto LBL_ERR;
       }
    }
-   *outlen = 32*LTC_FORTUNA_POOLS;
+   *outlen = len;
    err = CRYPT_OK;
 
 LBL_ERR:
@@ -368,17 +390,18 @@
    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 @@
    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 @@
          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 @@
 #endif
 
 
-/* $Source$ */
-/* $Revision$ */
-/* $Date$ */
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */