| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- /* 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.
- *
- * Tom St Denis, [email protected], http://libtomcrypt.org
- */
- /* 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
- we reseed automatically when len(pool0) >= 64 or every FORTUNA_WD calls to the read function */
- #include "mycrypt.h"
- #ifdef FORTUNA
- /* requries SHA256 and AES */
- #if !(defined(RIJNDAEL) && defined(SHA256))
- #error FORTUNA requires SHA256 and RIJNDAEL (AES)
- #endif
- #ifndef FORTUNA_POOLS
- #warning FORTUNA_POOLS was not previously defined (old headers?)
- #define FORTUNA_POOLS 32
- #endif
- #if FORTUNA_POOLS < 4 || FORTUNA_POOLS > 32
- #error FORTUNA_POOLS must be in [4..32]
- #endif
- const struct _prng_descriptor fortuna_desc = {
- "fortuna", 1024,
- &fortuna_start,
- &fortuna_add_entropy,
- &fortuna_ready,
- &fortuna_read,
- &fortuna_done,
- &fortuna_export,
- &fortuna_import,
- &fortuna_test
- };
- /* update the IV */
- static void fortuna_update_iv(prng_state *prng)
- {
- int x;
- unsigned char *IV;
- /* update IV */
- IV = prng->fortuna.IV;
- for (x = 0; x < 16; x++) {
- IV[x] = (IV[x] + 1) & 255;
- if (IV[x] != 0) break;
- }
- }
- /* reseed the PRNG */
- static int fortuna_reseed(prng_state *prng)
- {
- unsigned char tmp[MAXBLOCKSIZE];
- hash_state md;
- int err, x;
- ++prng->fortuna.reset_cnt;
- /* new K == SHA256(K || s) where s == SHA256(P0) || SHA256(P1) ... */
- sha256_init(&md);
- if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) {
- return err;
- }
- for (x = 0; x < FORTUNA_POOLS; x++) {
- 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) {
- return err;
- }
- /* add it to the string */
- if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) {
- return err;
- }
- /* reset this pool */
- sha256_init(&prng->fortuna.pool[x]);
- } else {
- break;
- }
- }
- /* finish key */
- if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
- return err;
- }
- if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
- return err;
- }
- fortuna_update_iv(prng);
- /* reset pool len */
- prng->fortuna.pool0_len = 0;
- prng->fortuna.wd = 0;
- #ifdef CLEAN_STACK
- zeromem(&md, sizeof(md));
- zeromem(tmp, sizeof(tmp));
- #endif
- return CRYPT_OK;
- }
- int fortuna_start(prng_state *prng)
- {
- int err, x;
- _ARGCHK(prng != NULL);
-
- /* initialize the pools */
- for (x = 0; x < FORTUNA_POOLS; x++) {
- sha256_init(&prng->fortuna.pool[x]);
- }
- prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.reset_cnt =
- prng->fortuna.wd = 0;
- /* reset bufs */
- zeromem(prng->fortuna.K, 32);
- if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
- return err;
- }
- zeromem(prng->fortuna.IV, 16);
- return CRYPT_OK;
- }
- int fortuna_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
- {
- unsigned char tmp[2];
- int err;
- _ARGCHK(buf != NULL);
- _ARGCHK(prng != NULL);
- /* ensure len <= 32 */
- if (len > 32) {
- return CRYPT_INVALID_ARG;
- }
- /* add s || length(buf) || buf to pool[pool_idx] */
- tmp[0] = 0;
- tmp[1] = len;
- if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) {
- return err;
- }
- if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], buf, len)) != CRYPT_OK) {
- return err;
- }
- if (prng->fortuna.pool_idx == 0) {
- prng->fortuna.pool0_len += len;
- }
- if (++(prng->fortuna.pool_idx) == FORTUNA_POOLS) {
- prng->fortuna.pool_idx = 0;
- }
- return CRYPT_OK;
- }
- int fortuna_ready(prng_state *prng)
- {
- return fortuna_reseed(prng);
- }
- unsigned long fortuna_read(unsigned char *dst, unsigned long len, prng_state *prng)
- {
- unsigned char tmp[16];
- int err;
- unsigned long tlen;
- _ARGCHK(dst != NULL);
- _ARGCHK(prng != NULL);
- /* do we have to reseed? */
- if (++prng->fortuna.wd == FORTUNA_WD || prng->fortuna.pool0_len >= 64) {
- if ((err = fortuna_reseed(prng)) != CRYPT_OK) {
- return 0;
- }
- }
- /* now generate the blocks required */
- tlen = len;
- /* handle whole blocks without the extra memcpy */
- while (len >= 16) {
- /* encrypt the IV and store it */
- rijndael_ecb_encrypt(prng->fortuna.IV, dst, &prng->fortuna.skey);
- dst += 16;
- len -= 16;
- fortuna_update_iv(prng);
- }
- /* left over bytes? */
- if (len > 0) {
- rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
- XMEMCPY(dst, tmp, len);
- 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) {
- return 0;
- }
- #ifdef CLEAN_STACK
- zeromem(tmp, sizeof(tmp));
- #endif
- return tlen;
- }
- int fortuna_done(prng_state *prng)
- {
- int err, x;
- unsigned char tmp[32];
- _ARGCHK(prng != NULL);
- /* terminate all the hashes */
- for (x = 0; x < FORTUNA_POOLS; x++) {
- if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) {
- return err;
- }
- }
- /* call cipher done when we invent one ;-) */
- #ifdef CLEAN_STACK
- zeromem(tmp, sizeof(tmp));
- #endif
- return CRYPT_OK;
- }
- int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
- {
- int x, err;
- hash_state *md;
- _ARGCHK(out != NULL);
- _ARGCHK(outlen != NULL);
- _ARGCHK(prng != NULL);
- /* we'll write bytes for s&g's */
- if (*outlen < 32*FORTUNA_POOLS) {
- return CRYPT_BUFFER_OVERFLOW;
- }
- md = XMALLOC(sizeof(hash_state));
- if (md == NULL) {
- return CRYPT_MEM;
- }
- /* 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 < 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 __ERR;
- }
- /* now hash it */
- sha256_init(md);
- if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) {
- goto __ERR;
- }
- if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
- goto __ERR;
- }
- }
- *outlen = 32*FORTUNA_POOLS;
- err = CRYPT_OK;
- __ERR:
- #ifdef CLEAN_STACK
- zeromem(md, sizeof(*md));
- #endif
- XFREE(md);
- return err;
- }
-
- int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
- {
- int err, x;
- _ARGCHK(in != NULL);
- _ARGCHK(prng != NULL);
- if (inlen != 32*FORTUNA_POOLS) {
- return CRYPT_INVALID_ARG;
- }
- if ((err = fortuna_start(prng)) != CRYPT_OK) {
- return err;
- }
- for (x = 0; x < FORTUNA_POOLS; x++) {
- if ((err = fortuna_add_entropy(in+x*32, 32, prng)) != CRYPT_OK) {
- return err;
- }
- }
- return err;
- }
- int fortuna_test(void)
- {
- #ifndef LTC_TEST
- return CRYPT_NOP;
- #else
- int err;
- if ((err = sha256_test()) != CRYPT_OK) {
- return err;
- }
- return rijndael_test();
- #endif
- }
- #endif
|