Update to libtomcrypt 1.18.1, merged with Dropbear changes

This commit is contained in:
Matt Johnston
2018-02-09 21:44:05 +08:00
parent d72f50ff32
commit 4f2eb1914b
516 changed files with 87083 additions and 11842 deletions

View File

@@ -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$ */

View File

@@ -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->fortuna.prng_lock);
LTC_MUTEX_LOCK(&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);
}
/* 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 @@ 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$ */

View File

@@ -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;
}
}
unsigned char buf[256];
unsigned long i;
int err;
while (inlen--) {
prng->rc4.buf[prng->rc4.x++] = *in++;
}
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen > 0);
return CRYPT_OK;
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;
unsigned char buf[256] = { 0 };
unsigned long len;
int err, i;
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(prng != NULL);
/* extract the key */
s = prng->rc4.buf;
XMEMCPY(key, s, 256);
keylen = prng->rc4.x;
/* 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
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);
LTC_ARGCHK(prng != NULL);
unsigned long len = rc4_desc.export_size;
if (*outlen < 32) {
*outlen = 32;
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
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);
if (inlen != 32) {
return CRYPT_INVALID_ARG;
}
if ((err = rc4_start(prng)) != CRYPT_OK) {
return err;
}
return rc4_add_entropy(in, 32, prng);
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(in != NULL);
if (inlen < (unsigned long)rc4_desc.export_size) return CRYPT_INVALID_ARG;
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$ */

View File

@@ -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$ */

View File

@@ -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$ */

View File

@@ -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 =
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
"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;
unsigned char buf[40];
unsigned long i;
int err;
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(prng != NULL);
c = &(prng->sober128);
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(inlen > 0);
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;
}
return CRYPT_OK;
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);
LTC_ARGCHK(prng != NULL);
unsigned long len = sober128_desc.export_size;
if (*outlen < 64) {
*outlen = 64;
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
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);
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);
LTC_ARGCHK(prng != NULL);
LTC_ARGCHK(in != NULL);
if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG;
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[] = {
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;
{
16, 4, 20,
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;
/* 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;
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;
}
/* 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$ */

View File

@@ -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$ */

View File

@@ -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$ */