diff options
author | Matt Johnston <matt@ucc.asn.au> | 2018-02-17 19:29:51 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2018-02-17 19:29:51 +0800 |
commit | 7e8094d53a1c01ac671156ff2e67157b64d01a3a (patch) | |
tree | c88345f5bdd118eb9414dff5ab5c307bb1806c57 /libtomcrypt/src/prngs | |
parent | f7a664f127d3dfde0e7c7a9ca74b1d14f9a2f983 (diff) | |
parent | f042eb41ab0d31f8ba0c5ccc9c848ad01f08f986 (diff) |
merge from main
--HG--
branch : fuzz
Diffstat (limited to 'libtomcrypt/src/prngs')
-rw-r--r-- | libtomcrypt/src/prngs/chacha20.c | 247 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/fortuna.c | 181 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/rc4.c | 299 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/rng_get_bytes.c | 85 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/rng_make_prng.c | 18 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/sober128.c | 525 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/sprng.c | 59 | ||||
-rw-r--r-- | libtomcrypt/src/prngs/yarrow.c | 170 |
8 files changed, 805 insertions, 779 deletions
diff --git a/libtomcrypt/src/prngs/chacha20.c b/libtomcrypt/src/prngs/chacha20.c new file mode 100644 index 0000000..72a6d63 --- /dev/null +++ b/libtomcrypt/src/prngs/chacha20.c @@ -0,0 +1,247 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + */ + + /* the idea of re-keying loosely follows the approach used in: + * http://bxr.su/OpenBSD/lib/libc/crypt/arc4random.c + */ + +#include "tomcrypt.h" + +#ifdef LTC_CHACHA20_PRNG + +const struct ltc_prng_descriptor chacha20_prng_desc = +{ + "chacha20", + 40, + &chacha20_prng_start, + &chacha20_prng_add_entropy, + &chacha20_prng_ready, + &chacha20_prng_read, + &chacha20_prng_done, + &chacha20_prng_export, + &chacha20_prng_import, + &chacha20_prng_test +}; + +/** + Start the PRNG + @param prng The PRNG state to initialize + @return CRYPT_OK if successful +*/ +int chacha20_prng_start(prng_state *prng) +{ + LTC_ARGCHK(prng != NULL); + prng->ready = 0; + XMEMSET(&prng->chacha.ent, 0, sizeof(prng->chacha.ent)); + prng->chacha.idx = 0; + LTC_MUTEX_INIT(&prng->lock) + return CRYPT_OK; +} + +/** + Add entropy to the PRNG state + @param in The data to add + @param inlen Length of the data to add + @param prng PRNG state to update + @return CRYPT_OK if successful +*/ +int chacha20_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) +{ + unsigned char buf[40]; + unsigned long i; + int err; + + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen > 0); + + LTC_MUTEX_LOCK(&prng->lock); + if (prng->ready) { + /* chacha20_prng_ready() was already called, do "rekey" operation */ + if ((err = chacha_keystream(&prng->chacha.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; + for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i]; + /* key 32 bytes, 20 rounds */ + if ((err = chacha_setup(&prng->chacha.s, buf, 32, 20)) != CRYPT_OK) goto LBL_UNLOCK; + /* iv 8 bytes */ + if ((err = chacha_ivctr64(&prng->chacha.s, buf + 32, 8, 0)) != CRYPT_OK) goto LBL_UNLOCK; + /* clear KEY + IV */ + zeromem(buf, sizeof(buf)); + } + else { + /* chacha20_prng_ready() was not called yet, add entropy to ent buffer */ + while (inlen--) prng->chacha.ent[prng->chacha.idx++ % sizeof(prng->chacha.ent)] ^= *in++; + } + err = 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 chacha20_prng_ready(prng_state *prng) +{ + int err; + + LTC_ARGCHK(prng != NULL); + + LTC_MUTEX_LOCK(&prng->lock); + if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; } + /* key 32 bytes, 20 rounds */ + if ((err = chacha_setup(&prng->chacha.s, prng->chacha.ent, 32, 20)) != CRYPT_OK) goto LBL_UNLOCK; + /* iv 8 bytes */ + if ((err = chacha_ivctr64(&prng->chacha.s, prng->chacha.ent + 32, 8, 0)) != CRYPT_OK) goto LBL_UNLOCK; + XMEMSET(&prng->chacha.ent, 0, sizeof(prng->chacha.ent)); + prng->chacha.idx = 0; + prng->ready = 1; +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return err; +} + +/** + Read from the PRNG + @param out Destination + @param outlen Length of output + @param prng The active PRNG to read from + @return Number of octets read +*/ +unsigned long chacha20_prng_read(unsigned char *out, unsigned long outlen, prng_state *prng) +{ + if (outlen == 0 || prng == NULL || out == NULL) return 0; + LTC_MUTEX_LOCK(&prng->lock); + if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; } + if (chacha_keystream(&prng->chacha.s, out, outlen) != CRYPT_OK) outlen = 0; +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return outlen; +} + +/** + Terminate the PRNG + @param prng The PRNG to terminate + @return CRYPT_OK if successful +*/ +int chacha20_prng_done(prng_state *prng) +{ + int err; + LTC_ARGCHK(prng != NULL); + LTC_MUTEX_LOCK(&prng->lock); + prng->ready = 0; + err = chacha_done(&prng->chacha.s); + LTC_MUTEX_UNLOCK(&prng->lock); + LTC_MUTEX_DESTROY(&prng->lock); + return err; +} + +/** + Export the PRNG state + @param out [out] Destination + @param outlen [in/out] Max size and resulting size of the state + @param prng The PRNG to export + @return CRYPT_OK if successful +*/ +int chacha20_prng_export(unsigned char *out, unsigned long *outlen, prng_state *prng) +{ + unsigned long len = chacha20_prng_desc.export_size; + + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + if (*outlen < len) { + *outlen = len; + return CRYPT_BUFFER_OVERFLOW; + } + + if (chacha20_prng_read(out, len, prng) != len) { + return CRYPT_ERROR_READPRNG; + } + + *outlen = len; + return CRYPT_OK; +} + +/** + 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 chacha20_prng_import(const unsigned char *in, unsigned long inlen, prng_state *prng) +{ + int err; + + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(in != NULL); + if (inlen < (unsigned long)chacha20_prng_desc.export_size) return CRYPT_INVALID_ARG; + + if ((err = chacha20_prng_start(prng)) != CRYPT_OK) return err; + if ((err = chacha20_prng_add_entropy(in, inlen, prng)) != CRYPT_OK) return err; + return CRYPT_OK; +} + +/** + PRNG self-test + @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled +*/ +int chacha20_prng_test(void) +{ +#ifndef LTC_TEST + return CRYPT_NOP; +#else + prng_state st; + unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 }; + unsigned char dmp[300]; + unsigned long dmplen = sizeof(dmp); + unsigned char out[500]; + unsigned char t1[] = { 0x59, 0xB2, 0x26, 0x95, 0x2B, 0x01, 0x8F, 0x05, 0xBE, 0xD8 }; + unsigned char t2[] = { 0x47, 0xC9, 0x0D, 0x03, 0xE4, 0x75, 0x34, 0x27, 0xBD, 0xDE }; + unsigned char t3[] = { 0xBC, 0xFA, 0xEF, 0x59, 0x37, 0x7F, 0x1A, 0x91, 0x1A, 0xA6 }; + int err; + + if ((err = chacha20_prng_start(&st)) != CRYPT_OK) return err; + /* add entropy to uninitialized prng */ + if ((err = chacha20_prng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if ((err = chacha20_prng_ready(&st)) != CRYPT_OK) return err; + if (chacha20_prng_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t1, sizeof(t1), "CHACHA-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR; + if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + /* add entropy to already initialized prng */ + if ((err = chacha20_prng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if ((err = chacha20_prng_export(dmp, &dmplen, &st)) != CRYPT_OK) return err; + if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if (chacha20_prng_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t2, sizeof(t2), "CHACHA-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR; + if ((err = chacha20_prng_done(&st)) != CRYPT_OK) return err; + if ((err = chacha20_prng_import(dmp, dmplen, &st)) != CRYPT_OK) return err; + if ((err = chacha20_prng_ready(&st)) != CRYPT_OK) return err; + if (chacha20_prng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if (chacha20_prng_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t3, sizeof(t3), "CHACHA-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR; + if ((err = chacha20_prng_done(&st)) != CRYPT_OK) return err; + + return CRYPT_OK; +#endif +} + +#endif + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ 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$ */ diff --git a/libtomcrypt/src/prngs/rc4.c b/libtomcrypt/src/prngs/rc4.c index 15c74e3..e2aa921 100644 --- a/libtomcrypt/src/prngs/rc4.c +++ b/libtomcrypt/src/prngs/rc4.c @@ -5,44 +5,45 @@ * * 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" /** - @file rc4.c - LTC_RC4 PRNG, Tom St Denis -*/ + @file prngs/rc4.c + RC4 PRNG, Tom St Denis +*/ #ifdef LTC_RC4 -const struct ltc_prng_descriptor rc4_desc = +const struct ltc_prng_descriptor rc4_desc = { - "rc4", 32, - &rc4_start, - &rc4_add_entropy, - &rc4_ready, - &rc4_read, - &rc4_done, - &rc4_export, - &rc4_import, - &rc4_test + "rc4", + 32, + &rc4_start, + &rc4_add_entropy, + &rc4_ready, + &rc4_read, + &rc4_done, + &rc4_export, + &rc4_import, + &rc4_test }; /** Start the PRNG @param prng [out] The PRNG state to initialize @return CRYPT_OK if successful -*/ +*/ int rc4_start(prng_state *prng) { - LTC_ARGCHK(prng != NULL); - - /* set keysize to zero */ - prng->rc4.x = 0; - - return CRYPT_OK; + LTC_ARGCHK(prng != NULL); + prng->ready = 0; + /* set entropy (key) size to zero */ + prng->rc4.s.x = 0; + /* clear entropy (key) buffer */ + XMEMSET(&prng->rc4.s.buf, 0, sizeof(prng->rc4.s.buf)); + LTC_MUTEX_INIT(&prng->lock) + return CRYPT_OK; } /** @@ -51,68 +52,63 @@ int rc4_start(prng_state *prng) @param inlen Length of the data to add @param prng PRNG state to update @return CRYPT_OK if successful -*/ +*/ int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) { - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(prng != NULL); - - /* trim as required */ - if (prng->rc4.x + inlen > 256) { - if (prng->rc4.x == 256) { - /* I can't possibly accept another byte, ok maybe a mint wafer... */ - return CRYPT_OK; - } else { - /* only accept part of it */ - inlen = 256 - prng->rc4.x; - } - } - - while (inlen--) { - prng->rc4.buf[prng->rc4.x++] = *in++; - } + unsigned char buf[256]; + unsigned long i; + int err; - return CRYPT_OK; - + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen > 0); + + LTC_MUTEX_LOCK(&prng->lock); + if (prng->ready) { + /* rc4_ready() was already called, do "rekey" operation */ + if ((err = rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; + for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i]; + /* initialize RC4 */ + if ((err = rc4_stream_setup(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; + /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */ + for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf)); + zeromem(buf, sizeof(buf)); + } + else { + /* rc4_ready() was not called yet, add entropy to the buffer */ + while (inlen--) prng->rc4.s.buf[prng->rc4.s.x++ % sizeof(prng->rc4.s.buf)] ^= *in++; + } + err = 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 rc4_ready(prng_state *prng) { - unsigned char key[256], tmp, *s; - int keylen, x, y, j; - - LTC_ARGCHK(prng != NULL); - - /* extract the key */ - s = prng->rc4.buf; - XMEMCPY(key, s, 256); - keylen = prng->rc4.x; + unsigned char buf[256] = { 0 }; + unsigned long len; + int err, i; - /* make LTC_RC4 perm and shuffle */ - for (x = 0; x < 256; x++) { - s[x] = x; - } - - for (j = x = y = 0; x < 256; x++) { - y = (y + prng->rc4.buf[x] + key[j++]) & 255; - if (j == keylen) { - j = 0; - } - tmp = s[x]; s[x] = s[y]; s[y] = tmp; - } - prng->rc4.x = 0; - prng->rc4.y = 0; - -#ifdef LTC_CLEAN_STACK - zeromem(key, sizeof(key)); -#endif + LTC_ARGCHK(prng != NULL); - return CRYPT_OK; + LTC_MUTEX_LOCK(&prng->lock); + if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; } + XMEMCPY(buf, prng->rc4.s.buf, sizeof(buf)); + /* initialize RC4 */ + len = MIN(prng->rc4.s.x, 256); /* TODO: we can perhaps always use all 256 bytes */ + if ((err = rc4_stream_setup(&prng->rc4.s, buf, len)) != CRYPT_OK) goto LBL_UNLOCK; + /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */ + for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf)); + prng->ready = 1; +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return err; } /** @@ -121,44 +117,33 @@ int rc4_ready(prng_state *prng) @param outlen Length of output @param prng The active PRNG to read from @return Number of octets read -*/ +*/ unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng) { - unsigned char x, y, *s, tmp; - unsigned long n; - - LTC_ARGCHK(out != NULL); - LTC_ARGCHK(prng != NULL); - -#ifdef LTC_VALGRIND - zeromem(out, outlen); -#endif - - n = outlen; - x = prng->rc4.x; - y = prng->rc4.y; - s = prng->rc4.buf; - while (outlen--) { - x = (x + 1) & 255; - y = (y + s[x]) & 255; - tmp = s[x]; s[x] = s[y]; s[y] = tmp; - tmp = (s[x] + s[y]) & 255; - *out++ ^= s[tmp]; - } - prng->rc4.x = x; - prng->rc4.y = y; - return n; + if (outlen == 0 || prng == NULL || out == NULL) return 0; + LTC_MUTEX_LOCK(&prng->lock); + if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; } + if (rc4_stream_keystream(&prng->rc4.s, out, outlen) != CRYPT_OK) outlen = 0; +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return outlen; } /** Terminate the PRNG @param prng The PRNG to terminate @return CRYPT_OK if successful -*/ +*/ int rc4_done(prng_state *prng) { + int err; LTC_ARGCHK(prng != NULL); - return CRYPT_OK; + LTC_MUTEX_LOCK(&prng->lock); + prng->ready = 0; + err = rc4_stream_done(&prng->rc4.s); + LTC_MUTEX_UNLOCK(&prng->lock); + LTC_MUTEX_DESTROY(&prng->lock); + return err; } /** @@ -167,103 +152,99 @@ int rc4_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 rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) { - LTC_ARGCHK(outlen != NULL); - LTC_ARGCHK(out != NULL); + unsigned long len = rc4_desc.export_size; + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); - if (*outlen < 32) { - *outlen = 32; + if (*outlen < len) { + *outlen = len; return CRYPT_BUFFER_OVERFLOW; } - if (rc4_read(out, 32, prng) != 32) { + if (rc4_read(out, len, prng) != len) { return CRYPT_ERROR_READPRNG; } - *outlen = 32; + *outlen = len; return CRYPT_OK; } - + /** 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 rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) { int err; - LTC_ARGCHK(in != NULL); + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(in != NULL); + if (inlen < (unsigned long)rc4_desc.export_size) return CRYPT_INVALID_ARG; - if (inlen != 32) { - return CRYPT_INVALID_ARG; - } - - if ((err = rc4_start(prng)) != CRYPT_OK) { - return err; - } - return rc4_add_entropy(in, 32, prng); + if ((err = rc4_start(prng)) != CRYPT_OK) return err; + if ((err = rc4_add_entropy(in, inlen, prng)) != CRYPT_OK) return err; + return CRYPT_OK; } /** PRNG self-test @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled -*/ +*/ int rc4_test(void) { -#if !defined(LTC_TEST) || defined(LTC_VALGRIND) +#ifndef LTC_TEST return CRYPT_NOP; #else - static const struct { - unsigned char key[8], pt[8], ct[8]; - } tests[] = { -{ - { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, - { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, - { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 } -} -}; - prng_state prng; - unsigned char dst[8]; - int err, x; + prng_state st; + unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 }; + unsigned char dmp[500]; + unsigned long dmplen = sizeof(dmp); + unsigned char out[1000]; + unsigned char t1[] = { 0xE0, 0x4D, 0x9A, 0xF6, 0xA8, 0x9D, 0x77, 0x53, 0xAE, 0x09 }; + unsigned char t2[] = { 0xEF, 0x80, 0xA2, 0xE6, 0x50, 0x91, 0xF3, 0x17, 0x4A, 0x8A }; + unsigned char t3[] = { 0x4B, 0xD6, 0x5C, 0x67, 0x99, 0x03, 0x56, 0x12, 0x80, 0x48 }; + int err; + + if ((err = rc4_start(&st)) != CRYPT_OK) return err; + /* add entropy to uninitialized prng */ + if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if ((err = rc4_ready(&st)) != CRYPT_OK) return err; + if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t1, sizeof(t1), "RC4-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR; + if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + /* add entropy to already initialized prng */ + if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if ((err = rc4_export(dmp, &dmplen, &st)) != CRYPT_OK) return err; + if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t2, sizeof(t2), "RC4-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR; + if ((err = rc4_done(&st)) != CRYPT_OK) return err; + if ((err = rc4_import(dmp, dmplen, &st)) != CRYPT_OK) return err; + if ((err = rc4_ready(&st)) != CRYPT_OK) return err; + if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t3, sizeof(t3), "RC4-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR; + if ((err = rc4_done(&st)) != CRYPT_OK) return err; - for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { - if ((err = rc4_start(&prng)) != CRYPT_OK) { - return err; - } - if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) { - return err; - } - if ((err = rc4_ready(&prng)) != CRYPT_OK) { - return err; - } - XMEMCPY(dst, tests[x].pt, 8); - if (rc4_read(dst, 8, &prng) != 8) { - return CRYPT_ERROR_READPRNG; - } - rc4_done(&prng); - if (XMEMCMP(dst, tests[x].ct, 8)) { -#if 0 - int y; - printf("\n\nLTC_RC4 failed, I got:\n"); - for (y = 0; y < 8; y++) printf("%02x ", dst[y]); - printf("\n"); -#endif - return CRYPT_FAIL_TESTVECTOR; - } - } return CRYPT_OK; #endif } #endif - -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/prngs/rng_get_bytes.c b/libtomcrypt/src/prngs/rng_get_bytes.c index b8cc6f5..4e9a063 100644 --- a/libtomcrypt/src/prngs/rng_get_bytes.c +++ b/libtomcrypt/src/prngs/rng_get_bytes.c @@ -5,42 +5,45 @@ * * 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" -/** +#ifdef LTC_RNG_GET_BYTES +/** @file rng_get_bytes.c portable way to get secure random bits to feed a PRNG (Tom St Denis) */ -#ifdef LTC_DEVRANDOM +#if defined(LTC_DEVRANDOM) && !defined(_WIN32) /* on *NIX read /dev/random */ -static unsigned long rng_nix(unsigned char *buf, unsigned long len, +static unsigned long _rng_nix(unsigned char *buf, unsigned long len, void (*callback)(void)) { #ifdef LTC_NO_FILE + LTC_UNUSED_PARAM(callback); + LTC_UNUSED_PARAM(buf); + LTC_UNUSED_PARAM(len); return 0; #else FILE *f; unsigned long x; -#ifdef TRY_URANDOM_FIRST + LTC_UNUSED_PARAM(callback); +#ifdef LTC_TRY_URANDOM_FIRST f = fopen("/dev/urandom", "rb"); if (f == NULL) -#endif /* TRY_URANDOM_FIRST */ +#endif /* LTC_TRY_URANDOM_FIRST */ f = fopen("/dev/random", "rb"); if (f == NULL) { return 0; } - + /* disable buffering */ if (setvbuf(f, NULL, _IONBF, 0) != 0) { fclose(f); return 0; - } - + } + x = (unsigned long)fread(buf, 1, (size_t)len, f); fclose(f); return x; @@ -49,21 +52,16 @@ static unsigned long rng_nix(unsigned char *buf, unsigned long len, #endif /* LTC_DEVRANDOM */ -/* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */ -#if defined(CLOCKS_PER_SEC) && !defined(WINCE) +#if !defined(_WIN32_WCE) #define ANSI_RNG -static unsigned long rng_ansic(unsigned char *buf, unsigned long len, +static unsigned long _rng_ansic(unsigned char *buf, unsigned long len, void (*callback)(void)) { clock_t t1; int l, acc, bits, a, b; - if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) { - return 0; - } - l = len; bits = 8; acc = a = b = 0; @@ -76,33 +74,37 @@ static unsigned long rng_ansic(unsigned char *buf, unsigned long len, } while (a == b); acc = (acc << 1) | a; } - *buf++ = acc; + *buf++ = acc; acc = 0; bits = 8; } - acc = bits = a = b = 0; return l; } -#endif +#endif /* Try the Microsoft CSP */ -#if defined(WIN32) || defined(WINCE) -#define _WIN32_WINNT 0x0400 -#ifdef WINCE +#if defined(_WIN32) || defined(_WIN32_WCE) +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#endif +#ifdef _WIN32_WCE #define UNDER_CE #define ARM #endif + +#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <wincrypt.h> -static unsigned long rng_win32(unsigned char *buf, unsigned long len, +static unsigned long _rng_win32(unsigned char *buf, unsigned long len, void (*callback)(void)) { HCRYPTPROV hProv = 0; - if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, - (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && - !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, + LTC_UNUSED_PARAM(callback); + if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && + !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) return 0; @@ -123,26 +125,35 @@ static unsigned long rng_win32(unsigned char *buf, unsigned long len, @param outlen Length desired (octets) @param callback Pointer to void function to act as "callback" when RNG is slow. This can be NULL @return Number of octets read -*/ -unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen, +*/ +unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen, void (*callback)(void)) { unsigned long x; LTC_ARGCHK(out != NULL); -#if defined(LTC_DEVRANDOM) - x = rng_nix(out, outlen, callback); if (x != 0) { return x; } +#ifdef LTC_PRNG_ENABLE_LTC_RNG + if (ltc_rng) { + x = ltc_rng(out, outlen, callback); + if (x != 0) { + return x; + } + } #endif -#ifdef WIN32 - x = rng_win32(out, outlen, callback); if (x != 0) { return x; } + +#if defined(_WIN32) || defined(_WIN32_WCE) + x = _rng_win32(out, outlen, callback); if (x != 0) { return x; } +#elif defined(LTC_DEVRANDOM) + x = _rng_nix(out, outlen, callback); if (x != 0) { return x; } #endif #ifdef ANSI_RNG - x = rng_ansic(out, outlen, callback); if (x != 0) { return x; } + x = _rng_ansic(out, outlen, callback); if (x != 0) { return x; } #endif return 0; } +#endif /* #ifdef LTC_RNG_GET_BYTES */ -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/prngs/rng_make_prng.c b/libtomcrypt/src/prngs/rng_make_prng.c index 6ba2cbe..b01c325 100644 --- a/libtomcrypt/src/prngs/rng_make_prng.c +++ b/libtomcrypt/src/prngs/rng_make_prng.c @@ -5,12 +5,11 @@ * * 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" -/** +#ifdef LTC_RNG_MAKE_PRNG +/** @file rng_make_prng.c portable way to get secure random bits to feed a PRNG (Tom St Denis) */ @@ -22,13 +21,13 @@ @param prng [out] PRNG state to initialize @param callback A pointer to a void function for when the RNG is slow, this can be NULL @return CRYPT_OK if successful -*/ -int rng_make_prng(int bits, int wprng, prng_state *prng, +*/ +int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void)) { unsigned char buf[256]; int err; - + LTC_ARGCHK(prng != NULL); /* check parameter */ @@ -62,8 +61,9 @@ int rng_make_prng(int bits, int wprng, prng_state *prng, #endif return CRYPT_OK; } +#endif /* #ifdef LTC_RNG_MAKE_PRNG */ -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/prngs/sober128.c b/libtomcrypt/src/prngs/sober128.c index 9bc7727..8d95491 100644 --- a/libtomcrypt/src/prngs/sober128.c +++ b/libtomcrypt/src/prngs/sober128.c @@ -5,196 +5,45 @@ * * 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" /** - @file sober128.c + @file prngs/sober128.c Implementation of SOBER-128 by Tom St Denis. Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM. */ #ifdef LTC_SOBER128 -#include "sober128tab.c" - -const struct ltc_prng_descriptor sober128_desc = -{ - "sober128", 64, - &sober128_start, - &sober128_add_entropy, - &sober128_ready, - &sober128_read, - &sober128_done, - &sober128_export, - &sober128_import, - &sober128_test +const struct ltc_prng_descriptor sober128_desc = +{ + "sober128", + 40, + &sober128_start, + &sober128_add_entropy, + &sober128_ready, + &sober128_read, + &sober128_done, + &sober128_export, + &sober128_import, + &sober128_test }; -/* don't change these... */ -#define N 17 -#define FOLD N /* how many iterations of folding to do */ -#define INITKONST 0x6996c53a /* value of KONST to use during key loading */ -#define KEYP 15 /* where to insert key words */ -#define FOLDP 4 /* where to insert non-linear feedback */ - -#define B(x,i) ((unsigned char)(((x) >> (8*i)) & 0xFF)) - -static ulong32 BYTE2WORD(unsigned char *b) -{ - ulong32 t; - LOAD32L(t, b); - return t; -} - -#define WORD2BYTE(w, b) STORE32L(b, w) - -static void XORWORD(ulong32 w, unsigned char *b) -{ - ulong32 t; - LOAD32L(t, b); - t ^= w; - STORE32L(t, b); -} - -/* give correct offset for the current position of the register, - * where logically R[0] is at position "zero". - */ -#define OFF(zero, i) (((zero)+(i)) % N) - -/* step the LFSR */ -/* After stepping, "zero" moves right one place */ -#define STEP(R,z) \ - R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF]; - -static void cycle(ulong32 *R) -{ - ulong32 t; - int i; - - STEP(R,0); - t = R[0]; - for (i = 1; i < N; ++i) { - R[i-1] = R[i]; - } - R[N-1] = t; -} - -/* Return a non-linear function of some parts of the register. - */ -#define NLFUNC(c,z) \ -{ \ - t = c->R[OFF(z,0)] + c->R[OFF(z,16)]; \ - t ^= Sbox[(t >> 24) & 0xFF]; \ - t = RORc(t, 8); \ - t = ((t + c->R[OFF(z,1)]) ^ c->konst) + c->R[OFF(z,6)]; \ - t ^= Sbox[(t >> 24) & 0xFF]; \ - t = t + c->R[OFF(z,13)]; \ -} - -static ulong32 nltap(struct sober128_prng *c) -{ - ulong32 t; - NLFUNC(c, 0); - return t; -} - /** Start the PRNG @param prng [out] The PRNG state to initialize @return CRYPT_OK if successful -*/ +*/ int sober128_start(prng_state *prng) { - int i; - struct sober128_prng *c; - - LTC_ARGCHK(prng != NULL); - - c = &(prng->sober128); - - /* Register initialised to Fibonacci numbers */ - c->R[0] = 1; - c->R[1] = 1; - for (i = 2; i < N; ++i) { - c->R[i] = c->R[i-1] + c->R[i-2]; - } - c->konst = INITKONST; - - /* next add_entropy will be the key */ - c->flag = 1; - c->set = 0; - - return CRYPT_OK; -} - -/* Save the current register state - */ -static void s128_savestate(struct sober128_prng *c) -{ - int i; - for (i = 0; i < N; ++i) { - c->initR[i] = c->R[i]; - } -} - -/* initialise to previously saved register state - */ -static void s128_reloadstate(struct sober128_prng *c) -{ - int i; - - for (i = 0; i < N; ++i) { - c->R[i] = c->initR[i]; - } -} - -/* Initialise "konst" - */ -static void s128_genkonst(struct sober128_prng *c) -{ - ulong32 newkonst; - - do { - cycle(c->R); - newkonst = nltap(c); - } while ((newkonst & 0xFF000000) == 0); - c->konst = newkonst; -} - -/* Load key material into the register - */ -#define ADDKEY(k) \ - c->R[KEYP] += (k); - -#define XORNL(nl) \ - c->R[FOLDP] ^= (nl); - -/* nonlinear diffusion of register for key */ -#define DROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); c->R[OFF((z+1),FOLDP)] ^= t; -static void s128_diffuse(struct sober128_prng *c) -{ - ulong32 t; - /* relies on FOLD == N == 17! */ - DROUND(0); - DROUND(1); - DROUND(2); - DROUND(3); - DROUND(4); - DROUND(5); - DROUND(6); - DROUND(7); - DROUND(8); - DROUND(9); - DROUND(10); - DROUND(11); - DROUND(12); - DROUND(13); - DROUND(14); - DROUND(15); - DROUND(16); + LTC_ARGCHK(prng != NULL); + prng->ready = 0; + XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent)); + prng->sober128.idx = 0; + LTC_MUTEX_INIT(&prng->lock) + return CRYPT_OK; } /** @@ -203,81 +52,63 @@ static void s128_diffuse(struct sober128_prng *c) @param inlen Length of the data to add @param prng PRNG state to update @return CRYPT_OK if successful -*/ +*/ int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) { - struct sober128_prng *c; - ulong32 i, k; - - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(prng != NULL); - c = &(prng->sober128); - - if (c->flag == 1) { - /* this is the first call to the add_entropy so this input is the key */ - /* inlen must be multiple of 4 bytes */ - if ((inlen & 3) != 0) { - return CRYPT_INVALID_KEYSIZE; - } - - for (i = 0; i < inlen; i += 4) { - k = BYTE2WORD((unsigned char *)&in[i]); - ADDKEY(k); - cycle(c->R); - XORNL(nltap(c)); - } - - /* also fold in the length of the key */ - ADDKEY(inlen); - - /* now diffuse */ - s128_diffuse(c); - - s128_genkonst(c); - s128_savestate(c); - c->nbuf = 0; - c->flag = 0; - c->set = 1; - } else { - /* ok we are adding an IV then... */ - s128_reloadstate(c); - - /* inlen must be multiple of 4 bytes */ - if ((inlen & 3) != 0) { - return CRYPT_INVALID_KEYSIZE; - } - - for (i = 0; i < inlen; i += 4) { - k = BYTE2WORD((unsigned char *)&in[i]); - ADDKEY(k); - cycle(c->R); - XORNL(nltap(c)); - } - - /* also fold in the length of the key */ - ADDKEY(inlen); - - /* now diffuse */ - s128_diffuse(c); - c->nbuf = 0; - } + unsigned char buf[40]; + unsigned long i; + int err; - return CRYPT_OK; + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen > 0); + + LTC_MUTEX_LOCK(&prng->lock); + if (prng->ready) { + /* sober128_ready() was already called, do "rekey" operation */ + if ((err = sober128_stream_keystream(&prng->sober128.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; + for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i]; + /* key 32 bytes, 20 rounds */ + if ((err = sober128_stream_setup(&prng->sober128.s, buf, 32)) != CRYPT_OK) goto LBL_UNLOCK; + /* iv 8 bytes */ + if ((err = sober128_stream_setiv(&prng->sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK; + /* clear KEY + IV */ + zeromem(buf, sizeof(buf)); + } + else { + /* sober128_ready() was not called yet, add entropy to ent buffer */ + while (inlen--) prng->sober128.ent[prng->sober128.idx++ % sizeof(prng->sober128.ent)] ^= *in++; + } + err = 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 sober128_ready(prng_state *prng) { - return prng->sober128.set == 1 ? CRYPT_OK : CRYPT_ERROR; -} + int err; -/* XOR pseudo-random bytes into buffer - */ -#define SROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); XORWORD(t, out+(z*4)); + LTC_ARGCHK(prng != NULL); + + LTC_MUTEX_LOCK(&prng->lock); + if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; } + /* key 32 bytes, 20 rounds */ + if ((err = sober128_stream_setup(&prng->sober128.s, prng->sober128.ent, 32)) != CRYPT_OK) goto LBL_UNLOCK; + /* iv 8 bytes */ + if ((err = sober128_stream_setiv(&prng->sober128.s, prng->sober128.ent + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK; + XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent)); + prng->sober128.idx = 0; + prng->ready = 1; +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return err; +} /** Read from the PRNG @@ -285,90 +116,33 @@ int sober128_ready(prng_state *prng) @param outlen Length of output @param prng The active PRNG to read from @return Number of octets read -*/ +*/ unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng) { - struct sober128_prng *c; - ulong32 t, tlen; - - LTC_ARGCHK(out != NULL); - LTC_ARGCHK(prng != NULL); - -#ifdef LTC_VALGRIND - zeromem(out, outlen); -#endif - - c = &(prng->sober128); - t = 0; - tlen = outlen; - - /* handle any previously buffered bytes */ - while (c->nbuf != 0 && outlen != 0) { - *out++ ^= c->sbuf & 0xFF; - c->sbuf >>= 8; - c->nbuf -= 8; - --outlen; - } - -#ifndef LTC_SMALL_CODE - /* do lots at a time, if there's enough to do */ - while (outlen >= N*4) { - SROUND(0); - SROUND(1); - SROUND(2); - SROUND(3); - SROUND(4); - SROUND(5); - SROUND(6); - SROUND(7); - SROUND(8); - SROUND(9); - SROUND(10); - SROUND(11); - SROUND(12); - SROUND(13); - SROUND(14); - SROUND(15); - SROUND(16); - out += 4*N; - outlen -= 4*N; - } -#endif - - /* do small or odd size buffers the slow way */ - while (4 <= outlen) { - cycle(c->R); - t = nltap(c); - XORWORD(t, out); - out += 4; - outlen -= 4; - } - - /* handle any trailing bytes */ - if (outlen != 0) { - cycle(c->R); - c->sbuf = nltap(c); - c->nbuf = 32; - while (c->nbuf != 0 && outlen != 0) { - *out++ ^= c->sbuf & 0xFF; - c->sbuf >>= 8; - c->nbuf -= 8; - --outlen; - } - } - - return tlen; + if (outlen == 0 || prng == NULL || out == NULL) return 0; + LTC_MUTEX_LOCK(&prng->lock); + if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; } + if (sober128_stream_keystream(&prng->sober128.s, out, outlen) != CRYPT_OK) outlen = 0; +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return outlen; } /** Terminate the PRNG @param prng The PRNG to terminate @return CRYPT_OK if successful -*/ +*/ int sober128_done(prng_state *prng) { + int err; LTC_ARGCHK(prng != NULL); - return CRYPT_OK; + LTC_MUTEX_LOCK(&prng->lock); + prng->ready = 0; + err = sober128_stream_done(&prng->sober128.s); + LTC_MUTEX_UNLOCK(&prng->lock); + LTC_MUTEX_DESTROY(&prng->lock); + return err; } /** @@ -377,124 +151,99 @@ int sober128_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 sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng) { - LTC_ARGCHK(outlen != NULL); - LTC_ARGCHK(out != NULL); + unsigned long len = sober128_desc.export_size; + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); - if (*outlen < 64) { - *outlen = 64; + if (*outlen < len) { + *outlen = len; return CRYPT_BUFFER_OVERFLOW; } - if (sober128_read(out, 64, prng) != 64) { + if (sober128_read(out, len, prng) != len) { return CRYPT_ERROR_READPRNG; } - *outlen = 64; + *outlen = len; return CRYPT_OK; } - + /** 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 sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng) { int err; - LTC_ARGCHK(in != NULL); + LTC_ARGCHK(prng != NULL); + LTC_ARGCHK(in != NULL); + if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG; - if (inlen != 64) { - return CRYPT_INVALID_ARG; - } - - if ((err = sober128_start(prng)) != CRYPT_OK) { - return err; - } - if ((err = sober128_add_entropy(in, 64, prng)) != CRYPT_OK) { - return err; - } - return sober128_ready(prng); + if ((err = sober128_start(prng)) != CRYPT_OK) return err; + if ((err = sober128_add_entropy(in, sober128_desc.export_size, prng)) != CRYPT_OK) return err; + return CRYPT_OK; } /** PRNG self-test @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled -*/ +*/ int sober128_test(void) { #ifndef LTC_TEST return CRYPT_NOP; #else - static const struct { - int keylen, ivlen, len; - unsigned char key[16], iv[4], out[20]; - } tests[] = { - -{ - 16, 4, 20, - - /* key */ - { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79, - 0x20, 0x31, 0x32, 0x38, 0x62, 0x69, 0x74, 0x73 }, - - /* IV */ - { 0x00, 0x00, 0x00, 0x00 }, - - /* expected output */ - { 0x43, 0x50, 0x0c, 0xcf, 0x89, 0x91, 0x9f, 0x1d, - 0xaa, 0x37, 0x74, 0x95, 0xf4, 0xb4, 0x58, 0xc2, - 0x40, 0x37, 0x8b, 0xbb } -} - -}; - prng_state prng; - unsigned char dst[20]; - int err, x; + prng_state st; + unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 }; + unsigned char dmp[300]; + unsigned long dmplen = sizeof(dmp); + unsigned char out[500]; + unsigned char t1[] = { 0x31, 0x82, 0xA7, 0xA5, 0x8B, 0xD7, 0xCB, 0x39, 0x86, 0x1A }; + unsigned char t2[] = { 0x6B, 0x43, 0x9E, 0xBC, 0xE7, 0x62, 0x9B, 0xE6, 0x9B, 0x83 }; + unsigned char t3[] = { 0x4A, 0x0E, 0x6C, 0xC1, 0xCF, 0xB4, 0x73, 0x49, 0x99, 0x05 }; + int err; - for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { - if ((err = sober128_start(&prng)) != CRYPT_OK) { - return err; - } - if ((err = sober128_add_entropy(tests[x].key, tests[x].keylen, &prng)) != CRYPT_OK) { - return err; - } - /* add IV */ - if ((err = sober128_add_entropy(tests[x].iv, tests[x].ivlen, &prng)) != CRYPT_OK) { - return err; - } + if ((err = sober128_start(&st)) != CRYPT_OK) return err; + /* add entropy to uninitialized prng */ + if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if ((err = sober128_ready(&st)) != CRYPT_OK) return err; + if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t1, sizeof(t1), "SOBER128-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR; + if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + /* add entropy to already initialized prng */ + if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if ((err = sober128_export(dmp, &dmplen, &st)) != CRYPT_OK) return err; + if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t2, sizeof(t2), "SOBER128-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR; + if ((err = sober128_done(&st)) != CRYPT_OK) return err; + if ((err = sober128_import(dmp, dmplen, &st)) != CRYPT_OK) return err; + if ((err = sober128_ready(&st)) != CRYPT_OK) return err; + if (sober128_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if (sober128_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ + if (compare_testvector(out, 10, t3, sizeof(t3), "SOBER128-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR; + if ((err = sober128_done(&st)) != CRYPT_OK) return err; - /* ready up */ - if ((err = sober128_ready(&prng)) != CRYPT_OK) { - return err; - } - XMEMSET(dst, 0, tests[x].len); - if (sober128_read(dst, tests[x].len, &prng) != (unsigned long)tests[x].len) { - return CRYPT_ERROR_READPRNG; - } - sober128_done(&prng); - if (XMEMCMP(dst, tests[x].out, tests[x].len)) { -#if 0 - printf("\n\nLTC_SOBER128 failed, I got:\n"); - for (y = 0; y < tests[x].len; y++) printf("%02x ", dst[y]); - printf("\n"); -#endif - return CRYPT_FAIL_TESTVECTOR; - } - } return CRYPT_OK; #endif } #endif - -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/prngs/sprng.c b/libtomcrypt/src/prngs/sprng.c index d86b081..b74d8da 100644 --- a/libtomcrypt/src/prngs/sprng.c +++ b/libtomcrypt/src/prngs/sprng.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,7 +12,7 @@ @file sprng.c Secure PRNG, Tom St Denis */ - + /* A secure PRNG using the RNG functions. Basically this is a * wrapper that allows you to use a secure RNG as a PRNG * in the various other functions. @@ -39,10 +37,11 @@ const struct ltc_prng_descriptor sprng_desc = Start the PRNG @param prng [out] The PRNG state to initialize @return CRYPT_OK if successful -*/ +*/ int sprng_start(prng_state *prng) { - return CRYPT_OK; + LTC_UNUSED_PARAM(prng); + return CRYPT_OK; } /** @@ -51,9 +50,12 @@ int sprng_start(prng_state *prng) @param inlen Length of the data to add @param prng PRNG state to update @return CRYPT_OK if successful -*/ +*/ int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) { + LTC_UNUSED_PARAM(in); + LTC_UNUSED_PARAM(inlen); + LTC_UNUSED_PARAM(prng); return CRYPT_OK; } @@ -61,9 +63,10 @@ int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state * Make the PRNG ready to read from @param prng The PRNG to make active @return CRYPT_OK if successful -*/ +*/ int sprng_ready(prng_state *prng) { + LTC_UNUSED_PARAM(prng); return CRYPT_OK; } @@ -73,10 +76,11 @@ int sprng_ready(prng_state *prng) @param outlen Length of output @param prng The active PRNG to read from @return Number of octets read -*/ +*/ unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng) { LTC_ARGCHK(out != NULL); + LTC_UNUSED_PARAM(prng); return rng_get_bytes(out, outlen, NULL); } @@ -84,9 +88,10 @@ unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *p Terminate the PRNG @param prng The PRNG to terminate @return CRYPT_OK if successful -*/ +*/ int sprng_done(prng_state *prng) { + LTC_UNUSED_PARAM(prng); return CRYPT_OK; } @@ -96,41 +101,61 @@ int sprng_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 sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng) { LTC_ARGCHK(outlen != NULL); + LTC_UNUSED_PARAM(out); + LTC_UNUSED_PARAM(prng); *outlen = 0; return CRYPT_OK; } - + /** 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 sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng) { + LTC_UNUSED_PARAM(in); + LTC_UNUSED_PARAM(inlen); + LTC_UNUSED_PARAM(prng); return CRYPT_OK; } /** PRNG self-test @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled -*/ +*/ int sprng_test(void) { +#ifndef LTC_TEST + return CRYPT_NOP; +#else + prng_state st; + unsigned char en[] = { 0x01, 0x02, 0x03, 0x04 }; + unsigned char out[1000]; + int err; + + if ((err = sprng_start(&st)) != CRYPT_OK) return err; + if ((err = sprng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; + if ((err = sprng_ready(&st)) != CRYPT_OK) return err; + if (sprng_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ + if ((err = sprng_done(&st)) != CRYPT_OK) return err; + return CRYPT_OK; +#endif } #endif - -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ + +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ diff --git a/libtomcrypt/src/prngs/yarrow.c b/libtomcrypt/src/prngs/yarrow.c index c94671f..e598834 100644 --- a/libtomcrypt/src/prngs/yarrow.c +++ b/libtomcrypt/src/prngs/yarrow.c @@ -5,15 +5,13 @@ * * 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" /** @file yarrow.c Yarrow PRNG, Tom St Denis -*/ +*/ #ifdef LTC_YARROW @@ -34,12 +32,13 @@ const struct ltc_prng_descriptor yarrow_desc = Start the PRNG @param prng [out] The PRNG state to initialize @return CRYPT_OK if successful -*/ +*/ int yarrow_start(prng_state *prng) { int err; - + LTC_ARGCHK(prng != NULL); + prng->ready = 0; /* these are the default hash/cipher combo used */ #ifdef LTC_RIJNDAEL @@ -64,13 +63,13 @@ int yarrow_start(prng_state *prng) prng->yarrow.cipher = register_cipher(&saferp_desc); #elif defined(LTC_RC2) prng->yarrow.cipher = register_cipher(&rc2_desc); -#elif defined(LTC_NOEKEON) +#elif defined(LTC_NOEKEON) prng->yarrow.cipher = register_cipher(&noekeon_desc); -#elif defined(LTC_ANUBIS) +#elif defined(LTC_ANUBIS) prng->yarrow.cipher = register_cipher(&anubis_desc); -#elif defined(LTC_KSEED) +#elif defined(LTC_KSEED) prng->yarrow.cipher = register_cipher(&kseed_desc); -#elif defined(LTC_KHAZAD) +#elif defined(LTC_KHAZAD) prng->yarrow.cipher = register_cipher(&khazad_desc); #elif defined(LTC_CAST5) prng->yarrow.cipher = register_cipher(&cast5_desc); @@ -120,7 +119,7 @@ int yarrow_start(prng_state *prng) /* zero the memory used */ zeromem(prng->yarrow.pool, sizeof(prng->yarrow.pool)); - LTC_MUTEX_INIT(&prng->yarrow.prng_lock) + LTC_MUTEX_INIT(&prng->lock) return CRYPT_OK; } @@ -131,78 +130,71 @@ int yarrow_start(prng_state *prng) @param inlen Length of the data to add @param prng PRNG state to update @return CRYPT_OK if successful -*/ +*/ int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) { hash_state md; int err; - LTC_ARGCHK(in != NULL); LTC_ARGCHK(prng != NULL); - - LTC_MUTEX_LOCK(&prng->yarrow.prng_lock); - + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen > 0); + + LTC_MUTEX_LOCK(&prng->lock); + if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } /* start the hash */ if ((err = hash_descriptor[prng->yarrow.hash].init(&md)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } /* hash the current pool */ - if ((err = hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool, + if ((err = hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool, hash_descriptor[prng->yarrow.hash].hashsize)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } /* add the new entropy */ if ((err = hash_descriptor[prng->yarrow.hash].process(&md, in, inlen)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } /* store result */ - if ((err = hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; - } + err = hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool); - LTC_MUTEX_UNLOCK(&prng->yarrow.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 yarrow_ready(prng_state *prng) { int ks, err; LTC_ARGCHK(prng != NULL); - LTC_MUTEX_LOCK(&prng->yarrow.prng_lock); + + LTC_MUTEX_LOCK(&prng->lock); if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } - + if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } /* setup CTR mode using the "pool" as the key */ ks = (int)hash_descriptor[prng->yarrow.hash].hashsize; if ((err = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } if ((err = ctr_start(prng->yarrow.cipher, /* what cipher to use */ @@ -211,11 +203,13 @@ int yarrow_ready(prng_state *prng) 0, /* number of rounds */ CTR_COUNTER_LITTLE_ENDIAN, /* little endian counter */ &prng->yarrow.ctr)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + goto LBL_UNLOCK; } - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return CRYPT_OK; + prng->ready = 1; + +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); + return err; } /** @@ -224,23 +218,28 @@ int yarrow_ready(prng_state *prng) @param outlen Length of output @param prng The active PRNG to read from @return Number of octets read -*/ +*/ unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng) { - LTC_ARGCHK(out != NULL); - LTC_ARGCHK(prng != NULL); + if (outlen == 0 || prng == NULL || out == NULL) return 0; - LTC_MUTEX_LOCK(&prng->yarrow.prng_lock); + LTC_MUTEX_LOCK(&prng->lock); + + if (!prng->ready) { + outlen = 0; + goto LBL_UNLOCK; + } /* put out in predictable state first */ zeromem(out, outlen); - + /* now randomize it */ if (ctr_encrypt(out, out, outlen, &prng->yarrow.ctr) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return 0; + outlen = 0; } - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); + +LBL_UNLOCK: + LTC_MUTEX_UNLOCK(&prng->lock); return outlen; } @@ -248,20 +247,22 @@ unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state * Terminate the PRNG @param prng The PRNG to terminate @return CRYPT_OK if successful -*/ +*/ int yarrow_done(prng_state *prng) { int err; LTC_ARGCHK(prng != NULL); - LTC_MUTEX_LOCK(&prng->yarrow.prng_lock); + LTC_MUTEX_LOCK(&prng->lock); + prng->ready = 0; /* call cipher done when we invent one ;-) */ /* we invented one */ err = ctr_done(&prng->yarrow.ctr); - - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); + + LTC_MUTEX_UNLOCK(&prng->lock); + LTC_MUTEX_DESTROY(&prng->lock); return err; } @@ -271,65 +272,52 @@ int yarrow_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 yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng) { + unsigned long len = yarrow_desc.export_size; + LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(prng != NULL); - LTC_MUTEX_LOCK(&prng->yarrow.prng_lock); - - /* we'll write 64 bytes for s&g's */ - if (*outlen < 64) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - *outlen = 64; + if (*outlen < len) { + *outlen = len; return CRYPT_BUFFER_OVERFLOW; } - if (yarrow_read(out, 64, prng) != 64) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); + if (yarrow_read(out, len, prng) != len) { return CRYPT_ERROR_READPRNG; } - *outlen = 64; + *outlen = len; return CRYPT_OK; } - + /** 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 yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng) { int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(prng != NULL); - - LTC_MUTEX_LOCK(&prng->yarrow.prng_lock); + if (inlen < (unsigned long)yarrow_desc.export_size) return CRYPT_INVALID_ARG; - if (inlen != 64) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return CRYPT_INVALID_ARG; - } - - if ((err = yarrow_start(prng)) != CRYPT_OK) { - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; - } - err = yarrow_add_entropy(in, 64, prng); - LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock); - return err; + if ((err = yarrow_start(prng)) != CRYPT_OK) return err; + if ((err = yarrow_add_entropy(in, inlen, prng)) != CRYPT_OK) return err; + return CRYPT_OK; } /** PRNG self-test @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled -*/ +*/ int yarrow_test(void) { #ifndef LTC_TEST @@ -341,13 +329,15 @@ int yarrow_test(void) if ((err = yarrow_start(&prng)) != CRYPT_OK) { return err; } - + /* now let's test the hash/cipher that was chosen */ - if ((err = cipher_descriptor[prng.yarrow.cipher].test()) != CRYPT_OK) { - return err; + if (cipher_descriptor[prng.yarrow.cipher].test && + ((err = cipher_descriptor[prng.yarrow.cipher].test()) != CRYPT_OK)) { + return err; } - if ((err = hash_descriptor[prng.yarrow.hash].test()) != CRYPT_OK) { - return err; + if (hash_descriptor[prng.yarrow.hash].test && + ((err = hash_descriptor[prng.yarrow.hash].test()) != CRYPT_OK)) { + return err; } return CRYPT_OK; @@ -357,6 +347,6 @@ int yarrow_test(void) #endif -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* ref: $Format:%D$ */ +/* git commit: $Format:%H$ */ +/* commit time: $Format:%ai$ */ |