Mercurial > dropbear
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$ */