|
@@ -37,7 +37,7 @@ we reseed automatically when len(pool0) >= 64 or every LTC_FORTUNA_WD calls to t
|
|
|
|
|
|
const struct ltc_prng_descriptor fortuna_desc = {
|
|
|
"fortuna",
|
|
|
- (32 * LTC_FORTUNA_POOLS), /* default: 1024 */
|
|
|
+ 64,
|
|
|
&fortuna_start,
|
|
|
&fortuna_add_entropy,
|
|
|
&fortuna_ready,
|
|
@@ -66,9 +66,9 @@ static int _fortuna_reseed(prng_state *prng)
|
|
|
{
|
|
|
unsigned char tmp[MAXBLOCKSIZE];
|
|
|
hash_state md;
|
|
|
+ ulong64 reset_cnt;
|
|
|
int err, x;
|
|
|
|
|
|
- ++prng->fortuna.reset_cnt;
|
|
|
|
|
|
/* new K == LTC_SHA256(K || s) where s == LTC_SHA256(P0) || LTC_SHA256(P1) ... */
|
|
|
sha256_init(&md);
|
|
@@ -77,8 +77,10 @@ static int _fortuna_reseed(prng_state *prng)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ reset_cnt = prng->fortuna.reset_cnt + 1;
|
|
|
+
|
|
|
for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
|
|
|
- if (x == 0 || ((prng->fortuna.reset_cnt >> (x-1)) & 1) == 0) {
|
|
|
+ if (x == 0 || ((reset_cnt >> (x-1)) & 1) == 0) {
|
|
|
/* terminate this hash */
|
|
|
if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
|
|
|
sha256_done(&md, tmp);
|
|
@@ -108,9 +110,10 @@ static int _fortuna_reseed(prng_state *prng)
|
|
|
}
|
|
|
_fortuna_update_iv(prng);
|
|
|
|
|
|
- /* reset pool len */
|
|
|
+ /* reset/update internals */
|
|
|
prng->fortuna.pool0_len = 0;
|
|
|
prng->fortuna.wd = 0;
|
|
|
+ prng->fortuna.reset_cnt = reset_cnt;
|
|
|
|
|
|
|
|
|
#ifdef LTC_CLEAN_STACK
|
|
@@ -121,6 +124,46 @@ static int _fortuna_reseed(prng_state *prng)
|
|
|
return CRYPT_OK;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ "Update Seed File"-compliant update of K
|
|
|
+
|
|
|
+ @param in The PRNG state
|
|
|
+ @param inlen Size of the state
|
|
|
+ @param prng The PRNG to import
|
|
|
+ @return CRYPT_OK if successful
|
|
|
+*/
|
|
|
+static int _fortuna_update_seed(const unsigned char *in, unsigned long inlen, prng_state *prng)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+ unsigned char tmp[MAXBLOCKSIZE];
|
|
|
+ hash_state md;
|
|
|
+
|
|
|
+ LTC_MUTEX_LOCK(&prng->lock);
|
|
|
+ /* new K = LTC_SHA256(K || in) */
|
|
|
+ sha256_init(&md);
|
|
|
+ if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) {
|
|
|
+ sha256_done(&md, tmp);
|
|
|
+ goto LBL_UNLOCK;
|
|
|
+ }
|
|
|
+ if ((err = sha256_process(&md, in, inlen)) != CRYPT_OK) {
|
|
|
+ sha256_done(&md, tmp);
|
|
|
+ goto LBL_UNLOCK;
|
|
|
+ }
|
|
|
+ /* finish key */
|
|
|
+ if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
|
|
|
+ goto LBL_UNLOCK;
|
|
|
+ }
|
|
|
+ _fortuna_update_iv(prng);
|
|
|
+
|
|
|
+LBL_UNLOCK:
|
|
|
+ LTC_MUTEX_UNLOCK(&prng->lock);
|
|
|
+#ifdef LTC_CLEAN_STACK
|
|
|
+ zeromem(&md, sizeof(md));
|
|
|
+#endif
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
Start the PRNG
|
|
|
@param prng [out] The PRNG state to initialize
|
|
@@ -251,6 +294,11 @@ unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /* ensure that one reseed happened before allowing to read */
|
|
|
+ if (prng->fortuna.reset_cnt == 0) {
|
|
|
+ goto LBL_UNLOCK;
|
|
|
+ }
|
|
|
+
|
|
|
/* now generate the blocks required */
|
|
|
tlen = outlen;
|
|
|
|
|
@@ -329,71 +377,7 @@ LBL_UNLOCK:
|
|
|
@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->lock);
|
|
|
-
|
|
|
- if (!prng->ready) {
|
|
|
- err = CRYPT_ERROR;
|
|
|
- goto LBL_UNLOCK;
|
|
|
- }
|
|
|
-
|
|
|
- /* we'll write bytes for s&g's */
|
|
|
- if (*outlen < len) {
|
|
|
- *outlen = len;
|
|
|
- err = CRYPT_BUFFER_OVERFLOW;
|
|
|
- goto LBL_UNLOCK;
|
|
|
- }
|
|
|
-
|
|
|
- md = XMALLOC(sizeof(hash_state));
|
|
|
- if (md == NULL) {
|
|
|
- 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
|
|
|
- */
|
|
|
- for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
|
|
|
- /* copy the PRNG */
|
|
|
- XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md));
|
|
|
-
|
|
|
- /* terminate it */
|
|
|
- if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
|
|
|
- goto LBL_ERR;
|
|
|
- }
|
|
|
-
|
|
|
- /* now hash it */
|
|
|
- if ((err = sha256_init(md)) != CRYPT_OK) {
|
|
|
- goto LBL_ERR;
|
|
|
- }
|
|
|
- if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) {
|
|
|
- goto LBL_ERR;
|
|
|
- }
|
|
|
- if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
|
|
|
- goto LBL_ERR;
|
|
|
- }
|
|
|
- }
|
|
|
- *outlen = len;
|
|
|
- err = CRYPT_OK;
|
|
|
-
|
|
|
-LBL_ERR:
|
|
|
-#ifdef LTC_CLEAN_STACK
|
|
|
- zeromem(md, sizeof(*md));
|
|
|
-#endif
|
|
|
- XFREE(md);
|
|
|
-LBL_UNLOCK:
|
|
|
- LTC_MUTEX_UNLOCK(&prng->lock);
|
|
|
- return err;
|
|
|
-}
|
|
|
+_LTC_PRNG_EXPORT(fortuna)
|
|
|
|
|
|
/**
|
|
|
Import a PRNG state
|
|
@@ -404,10 +388,10 @@ LBL_UNLOCK:
|
|
|
*/
|
|
|
int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
|
|
|
{
|
|
|
- int err, x;
|
|
|
+ int err;
|
|
|
|
|
|
- LTC_ARGCHK(in != NULL);
|
|
|
- LTC_ARGCHK(prng != NULL);
|
|
|
+ LTC_ARGCHK(in != NULL);
|
|
|
+ LTC_ARGCHK(prng != NULL);
|
|
|
|
|
|
if (inlen < (unsigned long)fortuna_desc.export_size) {
|
|
|
return CRYPT_INVALID_ARG;
|
|
@@ -416,12 +400,12 @@ int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prn
|
|
|
if ((err = fortuna_start(prng)) != CRYPT_OK) {
|
|
|
return err;
|
|
|
}
|
|
|
- for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
|
|
|
- if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) {
|
|
|
- return err;
|
|
|
- }
|
|
|
+
|
|
|
+ if ((err = _fortuna_update_seed(in, inlen, prng)) != CRYPT_OK) {
|
|
|
+ return err;
|
|
|
}
|
|
|
- return CRYPT_OK;
|
|
|
+
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
/**
|