From f6194bd50cadcf6bd8606e864334fddc2cfe1bb6 Mon Sep 17 00:00:00 2001 From: Sam Hartman Date: Thu, 8 Nov 2001 21:51:58 +0000 Subject: [PATCH] Add Yarrow from http://www.zeroknowledge.com/ This is version 0.1 of their Yarrow implementation. I have flattened the distribution, copying files in the src directory directly into this directory. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13969 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/crypto/yarrow/ASSUMPTIONS | 101 ++++ src/lib/crypto/yarrow/LICENSE | 21 + src/lib/crypto/yarrow/Makefile | 51 ++ src/lib/crypto/yarrow/README | 94 ++++ src/lib/crypto/yarrow/TODO | 9 + src/lib/crypto/yarrow/yarrow.c | 868 ++++++++++++++++++++++++++++++ src/lib/crypto/yarrow/yarrow.h | 199 +++++++ src/lib/crypto/yarrow/yarrow.man | 315 +++++++++++ src/lib/crypto/yarrow/yarrow.pod | 112 ++++ src/lib/crypto/yarrow/ycipher.h | 134 +++++ src/lib/crypto/yarrow/yexcep.h | 107 ++++ src/lib/crypto/yarrow/yhash.h | 40 ++ src/lib/crypto/yarrow/ylock.h | 18 + src/lib/crypto/yarrow/yseed.c | 297 ++++++++++ src/lib/crypto/yarrow/ystate.c | 109 ++++ src/lib/crypto/yarrow/ystate.h | 28 + src/lib/crypto/yarrow/ytest.c | 389 +++++++++++++ src/lib/crypto/yarrow/ytypes.h | 52 ++ 18 files changed, 2944 insertions(+) create mode 100644 src/lib/crypto/yarrow/ASSUMPTIONS create mode 100644 src/lib/crypto/yarrow/LICENSE create mode 100644 src/lib/crypto/yarrow/Makefile create mode 100644 src/lib/crypto/yarrow/README create mode 100644 src/lib/crypto/yarrow/TODO create mode 100644 src/lib/crypto/yarrow/yarrow.c create mode 100644 src/lib/crypto/yarrow/yarrow.h create mode 100644 src/lib/crypto/yarrow/yarrow.man create mode 100644 src/lib/crypto/yarrow/yarrow.pod create mode 100644 src/lib/crypto/yarrow/ycipher.h create mode 100644 src/lib/crypto/yarrow/yexcep.h create mode 100644 src/lib/crypto/yarrow/yhash.h create mode 100644 src/lib/crypto/yarrow/ylock.h create mode 100644 src/lib/crypto/yarrow/yseed.c create mode 100644 src/lib/crypto/yarrow/ystate.c create mode 100644 src/lib/crypto/yarrow/ystate.h create mode 100644 src/lib/crypto/yarrow/ytest.c create mode 100644 src/lib/crypto/yarrow/ytypes.h diff --git a/src/lib/crypto/yarrow/ASSUMPTIONS b/src/lib/crypto/yarrow/ASSUMPTIONS new file mode 100644 index 000000000..3e3c99c49 --- /dev/null +++ b/src/lib/crypto/yarrow/ASSUMPTIONS @@ -0,0 +1,101 @@ +Assumptions +=========== + +The Yarrow design, described in "Yarrow-160: Notes on the Design and +Analysis of the Yarrow Cryptographic Pseudonumber Generator" by John +Kelsey, Bruce Schneier and Niels Ferguson of Counterpane Systems +(available from http://www.counterpane.com/yarrow.html), left out some +implementation details and has some ambiguities in the protocol. ZKS +has to made some assumptions and taken some decisions in its +implementation of Yarrow. In the text, `we' represents ZKS. + +Here is the list of those assumptions: + +1) To simplify the code and speed up running time, we limit the number +of different sources to 20. This should be enough for most +applications. This can be changed by redefining YARROW_MAX_SOURCE in +yarrow.h. + +2) The Yarrow paper (in section 5.3) state that Pt is either +implementation dependent or dynamically adjusted. We chose to fix the +slow pool's Pt to 100 and the fast pool's Pt to 10. This can be +changed by redefining YARROW_FAST_PT and YARROW_SLOW_PT in yarrow.c. + +3) Initialization when there is no saved state is not discussed in the +Yarrow paper. We have defined that CPRNG is becomes seeded after a +slow reseed. During initialization, a slow reseed is triggered by +YARROW_K_OF_N_INIT_THRESH sources reaching the slow threshold +YARROW_SLOW_INIT_THRESH. During initialization, fast reseeds are +triggered when a source reaches the fast threshold +YARROW_FAST_INIT_THRESH. After reseed the behavior of the pools is +controlled by YARROW_K_OF_N_THRESH, YARROW_SLOW_THRESH and +YARROW_FAST_THRESH. + +Our default values for YARROW_K_OF_N_INIT_THRESH, +YARROW_SLOW_INIT_THRESH and YARROW_FAST_INIT_THRESH are the same as +YARROW_K_OF_N_THRESH, YARROW_SLOW_THRESH and YARROW_FAST_THRESH +respectively. Note this means that a Yarrow_Poll call by itself can +never put us in an initialized state, as it only works on one pool, +and the default YARROW_K_OF_N_INIT_THRESH value is 2. + +4) We define a function Yarrow_Poll which can gather entropy. The +user must allocate a source_id, and call Yarrow_Poll manually. +Yarrow_Poll just adds samples from the machines state to the source +given as an argument. + +5) Prior to initialization, Yarrow_Output will fail. + +6) The actions to take on state load are not described in the yarrow +paper, all it says is that 2k bytes should be written (and by +implication read back in somehow). We read in the 2k bytes, hash +them into the fast pool, and then do a forced fast reseed, and an +immediate state save. + +7) In step 2 of the reseed process, we must hash the value i. The +representation of this integer will affect the hash value. In our +code, i is a 64-bit unsigned value. We update the hash context using +the 64 bit big endian representation of i. + +8) Yarrow outputs random bits in blocks. If the calling function +requests less bits than available, then the unused bits are kept +in memory until the next call. In case of a reseed, we chose to +discard those leftover bits. + +9) The samples from one source must alternate between the two pools. +As a default, we initialize the first pool to send the sample too to +be the fast pool. This initialization is done only when a source is +added, not when we reseed from one. + +10) The Yarrow paper states that the maximum number of outputs between +reseeding is limited to min(2^n,2^(k/3)*Pg), but does not explain +what is to happen when this limit is reached. It could be the case +that we reach the limit but there is not enough entropy in the pools +to reseed. In our code, the Yarrow_Output_Block will do a forced +fast reseed. + +11) In the Yarrow paper, the limit on the number of outputs between +reseeding is expressed in number of outputs: + +#oututs <= min(2^n, 2^(k/3).Pg) + +but we redefine it in terms of gates by dividing the numbers by Pg, +the number of outputs per gate, and counting the number of gates +instead. This makes an overflow a little less likely. + +We don't use a bignum library, so in event of overflow, the limit in +number of gates before reseed (y->gates_limit) is reduced down to +2^64-1 (or 2^32-1 if 64 bit ints aren't available on the platform). + +12) The Yarrow paper describes that the cipher block C should be +incremented as part of the output function. We treat the bytes +of C as a big endian number to do the increment. + +13) Triple-DES key size. The yarrow paper uses the letter k to +represent the keysize in bits. Due to the parity bits, the size of k +is 192 bits. However the effective key size is actually 168 bits, as +the value of k is used in security limits, k must be 168 bits. The +paper uses k (eg set K to the next k output bits), so we have to do +the parity padding function, to copy bits 0-6 to 0-7, 7-13 to 8-15 +etc. The macro DES_Init performs the function of doing a DES key +schedule from a packed key (no parity bits), internally doing the +parity padding. Other ciphers are simpler as there is no parity. diff --git a/src/lib/crypto/yarrow/LICENSE b/src/lib/crypto/yarrow/LICENSE new file mode 100644 index 000000000..c85475d7e --- /dev/null +++ b/src/lib/crypto/yarrow/LICENSE @@ -0,0 +1,21 @@ +Copyright 2000 by Zero-Knowledge Systems, Inc. + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Zero-Knowledge Systems, +Inc. not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. Zero-Knowledge Systems, Inc. makes no representations +about the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +ZERO-KNOWLEDGE SYSTEMS, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL ZERO-KNOWLEDGE SYSTEMS, INC. BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/src/lib/crypto/yarrow/Makefile b/src/lib/crypto/yarrow/Makefile new file mode 100644 index 000000000..2dd864789 --- /dev/null +++ b/src/lib/crypto/yarrow/Makefile @@ -0,0 +1,51 @@ +CC=cc +AR=ar r +RM=rm -f + +# path to your OpenSSL installation +OPENSSL=/usr/local/ssl + +INC=-I$(OPENSSL)/include +LDFLAGS=-L$(OPENSSL) -L./ +LOADLIBES=-lyarrow -lcrypto #-lm + +# options you want to use +DEF1=-DYARROW_SAVE_STATE -DYARROW_TRACE #-DYARROW_DETECT_FORK +DEF2=-DYARROW_NO_MATHLIB +DEF=$(DEF1) $(DEF2) + +OPT=-g +#OPT=-O3 + +CFLAGS=$(OPT) $(DEF) $(INC) + +LIB=libyarrow.a +OBJS=yarrow.o ystate.o yseed.o +EXES=ytest + +ytest: ytest.o $(LIB) + $(CC) $(LDFLAGS) ytest.o $(LOADLIBES) -o $@ + +$(LIB): $(OBJS) + $(AR) $(LIB) $(OBJS) + +test: ytest + ./ytest + +clean: + $(RM) *.a *.o *~ *.bak $(EXES) core + +distclean: clean + $(RM) seed TAGS + +tags: + etags *.c *.h + +# DO NOT DELETE + +yarrow.o: yarrow.h ytypes.h yhash.h ycipher.h ylock.h ystate.h yexcep.h +yseed.o: yarrow.h ytypes.h yhash.h ycipher.h yexcep.h +ystate.o: yarrow.h ytypes.h yhash.h ycipher.h ystate.h yexcep.h +ytest.o: yarrow.h ytypes.h yhash.h ycipher.h yexcep.h +yarrow.o: ytypes.h yhash.h ycipher.h +ylock.o: yarrow.h ytypes.h yhash.h ycipher.h diff --git a/src/lib/crypto/yarrow/README b/src/lib/crypto/yarrow/README new file mode 100644 index 000000000..3dd4b801a --- /dev/null +++ b/src/lib/crypto/yarrow/README @@ -0,0 +1,94 @@ +Yarrow - Secure Pseudo-Random Number Generator +============================================== + +This is an implementation of the cryptographic pseudo-random number +generator Yarrow. You are encouraged to use, modify, and incorporate +this code. Please see the accompanying LICENSE file for more details. + + +Yarrow can be used with OpenSSL 0.9.5a (http://www.openssl.org) and +other cryptographic libraries. + +The Yarrow design is described in "Yarrow-160: Notes on the Design and +Analysis of the Yarrow Cryptographic Pseudorandom Number Generator" by +John Kelsey, Bruce Schneier and Niels Ferguson of Counterpane Systems, +available from http://www.counterpane.com/yarrow.html + +The Yarrow function calls are described in the yarrow(3) manpage. + +Installation +============ + +By default, Yarrow is built with OpenSSL. If the OpenSSL headers are +not installed in the standard directory /usr/local/ssl/include, +set the path in the Makefile. + +If it is possible that an application using Yarrow will fork(), Yarrow +must be compiled with -DYARROW_DETECT_FORK (then the child process +will have to seed Yarrow again), or the Yarrow_CTX must be allocated +in shared memory. + +If compiled with -DYARROW_SAVE_STATE, Yarrow will use a seed file +specified in the Yarrow_Init call. + +When the settings in the Makefile are correct, run "make". + + +Yarrow with OpenSSL: +------------------- + +The macros YARROW_CIPHER_3DES (default), YARROW_CIPHER_BLOWFISH and +YARROW_CIPHER_IDEA for ciphers and YARROW_HASH_SHA1 (default) and +YARROW_HASH_MD5 for hash functions are available to select algorithms +from OpenSSL. + +CRYPTO_set_locking_callback() is required in multithreaded applications. + + +Yarrow with other cryptographic libraries: +----------------------------------------- + +The Yarrow implementation uses a symmetric cipher, a cryptographic +hash function and a mutex. By default, Yarrow calls OpenSSL. For use +with other cryptographic libraries, the following types and macros +should be defined: + +Symmetric cipher - ycipher.h: + + typedef struct { ... } CIPHER_CTX; + + #define CIPHER_BLOCK_SIZE ... + #define CIPHER_KEY_SIZE ... + + void CIPHER_Init(CIPHER_CTX *ctx, void *key); + void CIPHER_Encrypt_Block(CIPHER_CTX *ctx, void *in, void *out); + +Hash function - yhash.h: + + typedef struct { ... } HASH_CTX; + + #define HASH_DIGEST_SIZE ... + #define HASH_STATE_SIZE ... + + void HASH_Init(HASH_CTX *ctx); + void HASH_Update(HASH_CTX *ctx, const void *data, unsigned long size); + void HASH_Final(HASH_CTX *ctx, unsigned char *md); + +Mutex - ylock.h: + + int LOCK(void); + int UNLOCK(void); + +Learn More: +---------- + +It is Zero-Knowledge's hope that third party developers of yarrow will +collaborate to derive test vectors for yarrow. In an effort to further +this discussion, we have created a mailing list for developers and +interested parties. To subscribe, send an email to +"yarrow-request@zeroknowledge.com" with "subscribe" in the body of the +message. + +For more information, or if you have questions or comments regarding open +source at Zero-Knowledge Systems, please visit +http://opensource.zeroknowledge.com diff --git a/src/lib/crypto/yarrow/TODO b/src/lib/crypto/yarrow/TODO new file mode 100644 index 000000000..bd133ecfd --- /dev/null +++ b/src/lib/crypto/yarrow/TODO @@ -0,0 +1,9 @@ +open issues: + +* when should the initial seed be considered complete? +* poll system ressources for randomness on startup? +* how frequently should the PRNG state be saved? +* how to react to fork()? +* what should the seed file contain, how should it be processed? +* test fork() hack +* test openSSL locks in multi-threaded environment diff --git a/src/lib/crypto/yarrow/yarrow.c b/src/lib/crypto/yarrow/yarrow.c new file mode 100644 index 000000000..74dc809cb --- /dev/null +++ b/src/lib/crypto/yarrow/yarrow.c @@ -0,0 +1,868 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +/* + * Yarrow - Cryptographic Pseudo-Random Number Generator + * Copyright (c) 2000 Zero-Knowledge Systems, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Zero-Knowledge Systems, + * Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Zero-Knowledge Systems, Inc. makes no representations + * about the suitability of this software for any purpose. It is + * provided "as is" without express or implied warranty. + * + * See the accompanying LICENSE file for more information. + */ + +#include +#include +#if !defined(WIN32) +# include +# if defined(macintosh) +# include +# else +# include +# endif +#endif +#if !defined(YARROW_NO_MATHLIB) +#include +#endif + +#define YARROW_IMPL +#include "yarrow.h" +#include "yhash.h" +#include "ycipher.h" +#include "ylock.h" +#include "ystate.h" +#include "yexcep.h" + +#if defined( YARROW_DEBUG ) || defined( YARROW_TRACE ) +# include +#endif + +#if defined( YARROW_TRACE ) +extern int yarrow_verbose; +#define TRACE( x ) do { if (yarrow_verbose) { x } } while (0) +#else +#define TRACE( x ) +#endif + +#if defined(macintosh) +# define make_big_endian32(x) (x) +#else +# define make_big_endian32(x) htonl(x) +#endif + +#if defined( YARROW_DEBUG ) +static void hex_print(FILE* f, const char* var, void* data, size_t size); +#endif + +static void block_increment( void* block, const int sz ); +#if defined( YARROW_SAVE_STATE ) +static int Yarrow_Load_State( Yarrow_CTX *y ); +static int Yarrow_Save_State( Yarrow_CTX *y ); +#endif + +static const byte zero_block[CIPHER_BLOCK_SIZE] = { 0, }; + +static const char* yarrow_str_error[] = { + "ok", + "failed", + "failed: uninitialized", + "failed: already initialized", + "failed: no driver", + "failed: can't open driver", + "failed: invalid source id", + "failed: no more source ids available", + "failed: invalid argument", + "failed: insufficient privileges", + "failed: out of memory", + "failed: resource exhausted", + "failed: not enough entropy to generate output", + "failed: locking error", + "failed: no state to load", + "failed: state load or save failed", + "failed: not implemented" +}; + +/* calculate limits after initialization */ + +static void Yarrow_Init_Limits(Yarrow_CTX* y) +{ + double tmp1, tmp2, limit; + /* max number of gates between reseeds -> exceed this, do forced reseed */ + + /* #oututs <= min(2^n, 2^(k/3).Pg) */ + + /* => #gates <= min(2^n/Pg, 2^(k/3)) */ + + tmp1 = POW_CIPHER_BLOCK_SIZE / y->Pg; + tmp2 = POW_CIPHER_KEY_SIZE; + limit = min(tmp1, tmp2); + if (limit < COUNTER_MAX) + { + y->gates_limit = limit; + } + else + { + y->gates_limit = COUNTER_MAX; + } +} + +/* if the program was forked, the child must not operate on the same + PRNG state */ +#ifdef YARROW_DETECT_FORK + +static int Yarrow_detect_fork(Yarrow_CTX *y) +{ + EXCEP_DECL; + + /* this does not work for multi-threaded apps if threads have different + * pids */ + if ( y->pid != getpid() ) + { + TRY( Yarrow_Init( y, y->entropyfile ) ); + } + + CATCH: + EXCEP_RET; +} + +#else + +#define Yarrow_detect_fork(x) (YARROW_OK) + +#endif + +static void Yarrow_Make_Seeded( Yarrow_CTX* y ) +{ + TRACE( printf( "SEEDED," ); ); + y->seeded = 1; + + /* now we are seeded switch to _THRESH values */ + + y->slow_thresh = YARROW_SLOW_THRESH; + y->fast_thresh = YARROW_FAST_THRESH; + y->slow_k_of_n_thresh = YARROW_K_OF_N_THRESH; +} + +YARROW_DLL +int Yarrow_Init(Yarrow_CTX* y, const char *filename) +{ + EXCEP_DECL; + int locked = 0; + + if (!y) { THROW( YARROW_BAD_ARG ); } + TRY( LOCK() ); + locked = 1; + + y->seeded = 0; + y->saved = 0; + +#if defined( YARROW_DETECT_FORK ) + y->pid = getpid(); +#endif + + y->entropyfile = filename; + y->num_sources = 0; + mem_zero(y->C, sizeof(y->C)); + HASH_Init(&y->pool[YARROW_FAST_POOL]); + HASH_Init(&y->pool[YARROW_SLOW_POOL]); + + mem_zero(y->K, sizeof(y->K)); + + CIPHER_Init(&y->cipher, y->K); + y->out_left = 0; + y->out_count = 0; + y->gate_count = 0; + y->Pg = YARROW_OUTPUTS_PER_GATE; + y->Pt[YARROW_FAST_POOL] = YARROW_FAST_PT; + y->Pt[YARROW_SLOW_POOL] = YARROW_SLOW_PT; + y->slow_k_of_n = 0; + + /* start with INIT_THRESH values, after seeded, switch to THRESH values */ + + y->slow_thresh = YARROW_SLOW_INIT_THRESH; + y->fast_thresh = YARROW_FAST_INIT_THRESH; + y->slow_k_of_n_thresh = YARROW_K_OF_N_INIT_THRESH; + + Yarrow_Init_Limits(y); + +#if defined( YARROW_SAVE_STATE ) + if ( y->entropyfile != NULL ) + { + int ret = Yarrow_Load_State( y ); + if ( ret != YARROW_OK && ret != YARROW_NO_STATE ) + { + THROW( ret ); + } + + /* if load suceeded then write new state back immediately + */ + + /* Also check that it's not already saved, because the reseed in + * Yarrow_Load_State may trigger a save + */ + + if ( ret == YARROW_OK && !y->saved ) + { + TRY( Yarrow_Save_State( y ) ); + } + } +#endif + + if ( !y->seeded ) + { + THROW( YARROW_NOT_SEEDED ); + } + + CATCH: + if ( locked ) { TRY( UNLOCK() ); } + EXCEP_RET; +} + +YARROW_DLL +int Yarrow_Input( Yarrow_CTX* y, unsigned source_id, + const void* sample, + size_t size, size_t entropy_bits ) +{ + EXCEP_DECL; + int ret; + int locked = 0; + Source* source; + size_t new_entropy; + size_t estimate; + + if (!y) { THROW( YARROW_BAD_ARG ); } + TRY( Yarrow_detect_fork( y ) ); + + if (source_id >= y->num_sources) { THROW( YARROW_BAD_SOURCE ); } + + source = &y->source[source_id]; + + if(source->pool != YARROW_FAST_POOL && source->pool != YARROW_SLOW_POOL) + { + THROW( YARROW_BAD_SOURCE ); + } + + TRY( LOCK() ); + locked = 1; + + /* hash in the sample */ + + HASH_Update(&y->pool[source->pool], (const void*)sample, size); + + /* only update entropy estimate if pool is not full */ + + if ( (source->pool == YARROW_FAST_POOL && + source->entropy[source->pool] < y->fast_thresh) || + (source->pool == YARROW_SLOW_POOL && + source->entropy[source->pool] < y->slow_thresh) ) + { + new_entropy = min(entropy_bits, size * 8 * YARROW_ENTROPY_MULTIPLIER); + if (source->estimator) + { + estimate = source->estimator(sample, size); + new_entropy = min(new_entropy, estimate); + } + source->entropy[source->pool] += new_entropy; + if ( source->entropy[source->pool] > YARROW_POOL_SIZE ) + { + source->entropy[source->pool] = YARROW_POOL_SIZE; + } + + if (source->pool == YARROW_FAST_POOL) + { + if (source->entropy[YARROW_FAST_POOL] >= y->fast_thresh) + { + ret = Yarrow_Reseed(y, YARROW_FAST_POOL); + if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED ) + { + THROW( ret ); + } + } + } + else + { + if (!source->reached_slow_thresh && + source->entropy[YARROW_SLOW_POOL] >= y->slow_thresh) + { + source->reached_slow_thresh = 1; + y->slow_k_of_n++; + if (y->slow_k_of_n >= y->slow_k_of_n_thresh) + { + y->slow_k_of_n = 0; + ret = Yarrow_Reseed(y, YARROW_SLOW_POOL); + if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED ) + { + THROW( ret ); + } + } + } + } + } + + /* put samples in alternate pools */ + + source->pool = (source->pool + 1) % 2; + + CATCH: + if ( locked ) { TRY( UNLOCK() ); } + EXCEP_RET; +} + +YARROW_DLL +int Yarrow_New_Source(Yarrow_CTX* y, unsigned* source_id) +{ + EXCEP_DECL; + int locked = 0; + Source* source; + + if (!y) { THROW( YARROW_BAD_ARG ); } + + TRY( LOCK() ); + locked = 1; + + if (y->num_sources + 1 > YARROW_MAX_SOURCES) + { + THROW( YARROW_TOO_MANY_SOURCES ); + } + + *source_id = y->num_sources; + + source = &y->source[*source_id]; + + source->pool = YARROW_FAST_POOL; + source->entropy[YARROW_FAST_POOL] = 0; + source->entropy[YARROW_SLOW_POOL] = 0; + source->reached_slow_thresh = 0; + source->estimator = 0; + + y->num_sources++; +CATCH: + if ( locked ) { TRY( UNLOCK() ); } + EXCEP_RET; +} + +int Yarrow_Register_Source_Estimator(Yarrow_CTX* y, unsigned source_id, + estimator_fn* fptr) +{ + EXCEP_DECL; + Source* source; + + if (!y) { THROW( YARROW_BAD_ARG ); } + if (source_id >= y->num_sources) { THROW( YARROW_BAD_SOURCE ); } + + source = &y->source[source_id]; + + source->estimator = fptr; + + CATCH: + EXCEP_RET; +} + +static int Yarrow_Output_Block( Yarrow_CTX* y, void* out ) +{ + EXCEP_DECL; + + if (!y || !out) { THROW( YARROW_BAD_ARG ); } + + TRACE( printf( "OUT," ); ); + + /* perform a gate function after Pg outputs */ + + y->out_count++; + if (y->out_count >= y->Pg) + { + y->out_count = 0; + TRY( Yarrow_Gate( y ) ); + + /* require new seed after reaching gates_limit */ + + y->gate_count++; + if ( y->gate_count >= y->gates_limit ) + { + y->gate_count = 0; + + /* not defined whether to do slow or fast reseed */ + + TRACE( printf( "OUTPUT LIMIT REACHED," ); ); + + TRY( Yarrow_Reseed( y, YARROW_SLOW_POOL ) ); + } + } + + /* C <- (C + 1) mod 2^n */ + + block_increment( y->C, CIPHER_BLOCK_SIZE ); + + /* R <- E_k(C) */ + + CIPHER_Encrypt_Block( &y->cipher, y->C, out ); + +#if defined(YARROW_DEBUG) + printf("===\n"); + hex_print( stdout, "output: C", y->C, CIPHER_BLOCK_SIZE ); + hex_print( stdout, "output: K", y->K, CIPHER_KEY_SIZE ); + hex_print( stdout, "output: O", out, CIPHER_BLOCK_SIZE ); +#endif + CATCH: + EXCEP_RET; +} + +YARROW_DLL +int Yarrow_Status( Yarrow_CTX* y, int *num_sources, unsigned *source_id, + size_t *entropy_bits, size_t *entropy_max ) +{ + EXCEP_DECL; + int num = y->slow_k_of_n_thresh; + int source = -1; + int emax = y->slow_thresh; + size_t entropy = 0; + unsigned i; + + if (!y) { THROW( YARROW_BAD_ARG ); } + TRY( Yarrow_detect_fork( y ) ); + + if (num_sources) { *num_sources = num; } + if (source_id) { *source_id = -1; } + if (entropy_bits) { *entropy_bits = 0; } + if (entropy_max) { *entropy_max = emax; } + + if (y->seeded) + { + if (num_sources) { *num_sources = 0; } + if (entropy_bits) { *entropy_bits = emax; } + THROW( YARROW_OK ); + } + + for (i = 0; i < y->num_sources; i++) + { + if (y->source[i].entropy[YARROW_SLOW_POOL] >= y->slow_thresh) + { + num--; + } + else if (y->source[i].entropy[YARROW_SLOW_POOL] > entropy) + { + source = i; + entropy = y->source[i].entropy[YARROW_SLOW_POOL]; + } + } + + if (num_sources) { *num_sources = num; } + if (source_id) { *source_id = source; } + if (entropy_bits) { *entropy_bits = entropy; } + THROW( YARROW_NOT_SEEDED ); + + CATCH: + EXCEP_RET; +} + +YARROW_DLL +int Yarrow_Output( Yarrow_CTX* y, void* out, size_t size ) +{ + EXCEP_DECL; + int locked = 0; + size_t left; + char* outp; + size_t use; + + if (!y || !out) { THROW( YARROW_BAD_ARG ); } + TRY( Yarrow_detect_fork( y ) ); + + if (!y->seeded) { THROW( YARROW_NOT_SEEDED ); } + + left = size; + outp = out; + + TRY( LOCK() ); + + if (y->out_left > 0) + { + use = min(left, y->out_left); + mem_copy(outp, y->out + CIPHER_BLOCK_SIZE - y->out_left, use); + left -= use; + y->out_left -= use; + outp += use; + } + + for ( ; + left >= CIPHER_BLOCK_SIZE; + left -= CIPHER_BLOCK_SIZE, outp += CIPHER_BLOCK_SIZE) + { + TRY( Yarrow_Output_Block(y, outp) ); + } + + if (left > 0) + { + TRY( Yarrow_Output_Block(y, y->out) ); + mem_copy(outp, y->out, left); + y->out_left = CIPHER_BLOCK_SIZE - left; + } + + CATCH: + if ( locked ) { TRY( UNLOCK() ); } + + EXCEP_RET; +} + +int Yarrow_Gate(Yarrow_CTX* y) +{ + EXCEP_DECL; + byte new_K[CIPHER_KEY_SIZE]; + + if (!y) { THROW( YARROW_BAD_ARG ); } + + TRACE( printf( "GATE[" ); ); + + /* K <- Next k bits of PRNG output */ + + TRY( Yarrow_Output(y, new_K, CIPHER_KEY_SIZE) ); + mem_copy(y->K, new_K, CIPHER_KEY_SIZE); + + /* need to resetup the key schedule as the key has changed */ + + CIPHER_Init(&y->cipher, y->K); + + CATCH: + TRACE( printf( "]," ); ); + mem_zero(new_K, sizeof(new_K)); + EXCEP_RET; +} + +#if defined( YARROW_SAVE_STATE ) +static int Yarrow_Load_State( Yarrow_CTX *y ) +{ + EXCEP_DECL; + Yarrow_STATE state; + + if ( !y ) { THROW( YARROW_BAD_ARG ); } + + if ( y->entropyfile ) + { + TRY( STATE_Load(y->entropyfile, &state) ); + TRACE( printf( "LOAD STATE," ); ); + +#if defined( YARROW_DEBUG ) + hex_print( stderr, "state.load", state.seed, sizeof(state.seed)); +#endif + + /* what to do here is not defined by the Yarrow paper */ + /* this is a place holder until we get some clarification */ + + HASH_Update( &y->pool[YARROW_FAST_POOL], + state.seed, sizeof(state.seed) ); + + Yarrow_Make_Seeded( y ); + + TRY( Yarrow_Reseed(y, YARROW_FAST_POOL) ); + } + CATCH: + mem_zero(state.seed, sizeof(state.seed)); + EXCEP_RET; +} + +static int Yarrow_Save_State( Yarrow_CTX *y ) +{ + EXCEP_DECL; + Yarrow_STATE state; + + if ( !y ) { THROW( YARROW_BAD_ARG ); } + + if ( y->entropyfile && y->seeded ) + { + TRACE( printf( "SAVE STATE[" ); ); + TRY( Yarrow_Output( y, state.seed, sizeof(state.seed) ) ); + TRY( STATE_Save(y->entropyfile, &state) ); + } + y->saved = 1; +# if defined(YARROW_DEBUG) + hex_print(stdout, "state.save", state.seed, sizeof(state.seed)); +# endif + + CATCH: + TRACE( printf( "]," ); ); + mem_zero(state.seed, sizeof(state.seed)); + EXCEP_RET; +} + +#endif + +int Yarrow_Reseed(Yarrow_CTX* y, int pool) +{ + EXCEP_DECL; + HASH_CTX* fast_pool = &y->pool[YARROW_FAST_POOL]; + HASH_CTX* slow_pool = &y->pool[YARROW_SLOW_POOL]; + byte digest[HASH_DIGEST_SIZE]; + HASH_CTX hash; + byte v_0[HASH_DIGEST_SIZE]; + byte v_i[HASH_DIGEST_SIZE]; + uint32 big_endian_int32; + COUNTER i; + + if (!y) { THROW( YARROW_BAD_ARG ); } + if( pool != YARROW_FAST_POOL && pool != YARROW_SLOW_POOL ) + { + THROW( YARROW_BAD_ARG ); + } + + TRACE( printf( "%s RESEED,", + pool == YARROW_SLOW_POOL ? "SLOW" : "FAST" ); ); + + if (pool == YARROW_SLOW_POOL) + { + /* SLOW RESEED */ + + /* feed hash of slow pool into the fast pool */ + + HASH_Final(slow_pool, digest); + + /* Each pool contains the running hash of all inputs fed into it + * since it was last used to carry out a reseed -- this implies + * that the pool must be reinitialized after a reseed + */ + + HASH_Init(slow_pool); /* reinitialize slow pool */ + HASH_Update(fast_pool, digest, sizeof(digest)); + + if (y->seeded == 0) + { + Yarrow_Make_Seeded( y ); + } + } + + /* step 1. v_0 <- hash of all inputs into fast pool */ + + HASH_Final(fast_pool, v_0); + HASH_Init(fast_pool); /* reinitialize fast pool */ + + /* v_i <- v_0 */ + + mem_copy( v_i, v_0, sizeof(v_0) ); + + /* step 2. v_i = h(v_{i-1}|v_0|i) for i = 1,..,Pt */ + + /* note: this code has to work for Pt = 0 also */ + + for ( i = 0; i < y->Pt[pool]; i++ ) + { + HASH_Init(&hash); + HASH_Update(&hash, v_i, sizeof(v_i)); + HASH_Update(&hash, v_0, sizeof(v_0)); + big_endian_int32 = make_big_endian32(i >> 32); /* MS word */ + HASH_Update(&hash, &big_endian_int32, sizeof(uint32)); + big_endian_int32 = make_big_endian32(i & 0xFFFFFFFF); /* LS word */ + HASH_Update(&hash, &big_endian_int32, sizeof(uint32)); + HASH_Final(&hash, v_i); + } + + /* step3. K = h'(h(v_Pt|K)) */ + + /* t = h(v_Pt|K) */ + + HASH_Init(&hash); + HASH_Update(&hash, v_i, sizeof(v_i)); + HASH_Update(&hash, y->K, sizeof(y->K)); + HASH_Final(&hash, v_i); + +#if defined(YARROW_DEBUG) + hex_print(stdout, "old K", y->K, sizeof(y->K)); +#endif + /* K <- h'(t) */ + + TRY( Yarrow_Stretch(v_i, HASH_DIGEST_SIZE, y->K, CIPHER_KEY_SIZE) ); + + /* need to resetup the key schedule as the key has changed */ + + CIPHER_Init(&y->cipher, y->K); + +#if defined(YARROW_DEBUG) + hex_print(stdout, "new K", y->K, sizeof(y->K)); +#endif + + /* step 4. C <- E_k(0) */ + +#if defined(YARROW_DEBUG) + hex_print(stdout, "old C", y->C, sizeof(y->C)); +#endif + CIPHER_Encrypt_Block(&y->cipher, zero_block, y->C); +#if defined(YARROW_DEBUG) + hex_print(stdout, "new C", y->C, sizeof(y->C)); +#endif + + /* discard part output from previous key */ + + y->out_left = 0; + + /* step 5. Reset all entropy estimate accumulators of the entropy + * accumulator to zero + */ + + for (i = 0; i < y->num_sources; i++) + { + y->source[i].entropy[pool] = 0; + if (pool == YARROW_SLOW_POOL) + { + /* if this is a slow reseed, reset the fast pool entropy + * accumulator also + */ + y->source[i].entropy[YARROW_FAST_POOL] = 0; + y->source[i].reached_slow_thresh = 0; + } + } + + /* step 7. If a seed file is in use, the next 2k bits of output + * are written to the seed file + */ + +#if defined( YARROW_SAVE_STATE ) + if ( y->seeded && y->entropyfile ) + { + TRY( Yarrow_Save_State( y ) ); + } +#endif + + CATCH: + /* step 6. Wipe the memory of all intermediate values + * + */ + + mem_zero( digest, sizeof(digest) ); + mem_zero( &hash, sizeof(hash) ); + mem_zero( v_0, sizeof(v_0) ); + mem_zero( v_i, sizeof(v_i) ); + + EXCEP_RET; +} + +int Yarrow_Stretch(const byte* m, size_t size, byte* out, size_t out_size) +{ + EXCEP_DECL; + const byte* s_i; + byte* outp; + int left, use; + HASH_CTX hash, save; + byte digest[HASH_DIGEST_SIZE]; + + if (m == NULL || size == 0 || out == NULL || out_size == 0) + { + THROW( YARROW_BAD_ARG ); + } + + /* + * s_0 = m + * s_1 = h(s_0 | ... | s_{i-1}) + * + * h'(m, k) = first k bits of (s_0 | s_1 | ...) + * + */ + + outp = out; + left = out_size; + + use = min(out_size, size); + mem_copy(outp, m, use); /* get k bits or as many as available */ + + s_i = (const byte*)m; /* pointer to s0 = m */ + outp += use; + left -= use; + + HASH_Init(&hash); + for ( ; + left > 0; + left -= HASH_DIGEST_SIZE) + { + HASH_Update(&hash, s_i, use); + + /* have to save hash state to one side as HASH_final changes state */ + + mem_copy(&save, &hash, sizeof(hash)); + HASH_Final(&hash, digest); + + use = min(HASH_DIGEST_SIZE, left); + mem_copy(outp, digest, use); + + /* put state back for next time */ + + mem_copy(&hash, &save, sizeof(hash)); + + s_i = outp; /* retain pointer to s_i */ + outp += use; + } + + CATCH: + mem_zero(&hash, sizeof(hash)); + mem_zero(digest, sizeof(digest)); + + EXCEP_RET; +} + +static void block_increment(void* block, const int sz) +{ + byte* b = block; + int i; + + for (i = sz-1; (++b[i]) == 0 && i > 0; i--) + { + ; /* nothing */ + } +} + +YARROW_DLL +int Yarrow_Final(Yarrow_CTX* y) +{ + EXCEP_DECL; + int locked = 0; + + if (!y) { THROW( YARROW_BAD_ARG ); } + TRY( Yarrow_detect_fork(y) ); + TRY( LOCK() ); + locked = 1; + +#if defined( YARROW_SAVE_STATE ) + if ( y->seeded && y->entropyfile ) + { + TRY( Yarrow_Save_State( y ) ); + } +#endif + + CATCH: + if ( locked ) { TRY( UNLOCK() ); } + mem_zero( y, sizeof(Yarrow_CTX) ); + EXCEP_RET; +} + +YARROW_DLL +const char* Yarrow_Str_Error( int err ) +{ + err = 1-err; + if ( err < 0 || err >= sizeof( yarrow_str_error ) / sizeof( char* ) ) + { + err = 1-YARROW_FAIL; + } + return yarrow_str_error[ err ]; +} + +#if defined(YARROW_DEBUG) +static void hex_print(FILE* f, const char* var, void* data, size_t size) +{ + const char* conv = "0123456789abcdef"; + size_t i; + char* p = (char*) data; + char c, d; + + fprintf(f, var); + fprintf(f, " = "); + for (i = 0; i < size; i++) + { + c = conv[(p[i] >> 4) & 0xf]; + d = conv[p[i] & 0xf]; + fprintf(f, "%c%c", c, d); + } + fprintf(f, "\n"); +} +#endif diff --git a/src/lib/crypto/yarrow/yarrow.h b/src/lib/crypto/yarrow/yarrow.h new file mode 100644 index 000000000..dc74a3ba0 --- /dev/null +++ b/src/lib/crypto/yarrow/yarrow.h @@ -0,0 +1,199 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YARROW_H +#define YARROW_H + +#if defined( YARROW_DETECT_FORK ) +#include +#endif + +#include "ytypes.h" +#include "yhash.h" +#include "ycipher.h" + +/* These error codes are returned by the functions below. */ + +#define YARROW_OK 1 /* All is well */ +#define YARROW_FAIL 0 /* generic failure */ +#define YARROW_NOT_INIT -1 /* YarrowInit hasn't been called */ +#define YARROW_ALREADY_INIT -2 /* YarrowInit has already been called */ +#define YARROW_NO_DRIVER -3 /* driver doesn't exist */ +#define YARROW_CANT_OPEN -4 /* can't open driver */ +#define YARROW_BAD_SOURCE -5 /* invalid source id */ +#define YARROW_TOO_MANY_SOURCES -6 /* can't create any more source ids */ +#define YARROW_BAD_ARG -7 /* invalid argument */ +#define YARROW_ACCESS -8 /* insufficient privileges */ +#define YARROW_NOMEM -9 /* out of memory */ +#define YARROW_NORSRC -10 /* a resource is exhausted */ +#define YARROW_NOT_SEEDED -11 /* not enough entropy to generate output */ +#define YARROW_LOCKING -12 /* locking error */ +#define YARROW_NO_STATE -13 /* there is no state to load */ +#define YARROW_STATE_ERROR -14 /* error with state load or save */ +#define YARROW_NOT_IMPL -15 /* not implemented */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Yarrow implementation and configuration parameters */ + +/* pool identification */ +#define YARROW_FAST_POOL 0 +#define YARROW_SLOW_POOL 1 + +#define YARROW_MAX_SOURCES 20 +#define YARROW_ENTROPY_MULTIPLIER 0.5 + +#define YARROW_POOL_SIZE (HASH_DIGEST_SIZE*8) + +#define YARROW_OUTPUTS_PER_GATE 10 /* Pg */ +#define YARROW_FAST_PT 10 +#define YARROW_SLOW_PT 100 + +/* thresholds to use once seeded */ + +#define YARROW_FAST_THRESH 100 +#define YARROW_SLOW_THRESH 160 +#define YARROW_K_OF_N_THRESH 2 + +/* The Yarrow paper does not specify when the initial seed should be + considered complete. Use the same conditions as a slow reseed */ + +#define YARROW_FAST_INIT_THRESH YARROW_FAST_THRESH +#define YARROW_SLOW_INIT_THRESH YARROW_SLOW_THRESH +#define YARROW_K_OF_N_INIT_THRESH YARROW_K_OF_N_THRESH + +/* sanity checks */ + +#if YARROW_FAST_THRESH > YARROW_POOL_SIZE +#error "can't have higher YARROW_FAST_THRESH than pool size" +#endif + +#if YARROW_SLOW_THRESH > YARROW_POOL_SIZE +#error "can't have higher YARROW_SLOW_THRESH than pool size" +#endif + +#if YARROW_FAST_INIT_THRESH > YARROW_POOL_SIZE +#error "can't have higher YARROW_FAST_INIT_THRESH than pool size" +#endif + +#if YARROW_SLOW_INIT_THRESH > YARROW_POOL_SIZE +#error "can't have higher YARROW_SLOW_INIT_THRESH than pool size" +#endif + +typedef size_t estimator_fn(const void* sample, size_t size); + +typedef struct +{ + int pool; + size_t entropy[2]; + int reached_slow_thresh; + estimator_fn* estimator; +} Source; + +typedef struct +{ + /* state */ + int seeded; + int saved; +#if defined( YARROW_DETECT_FORK ) + int pid; +#endif + Source source[YARROW_MAX_SOURCES]; + unsigned num_sources; + HASH_CTX pool[2]; + byte out[CIPHER_BLOCK_SIZE]; + unsigned out_left; + COUNTER out_count; + COUNTER gate_count; + COUNTER gates_limit; + byte C[CIPHER_BLOCK_SIZE]; + CIPHER_CTX cipher; + byte K[CIPHER_KEY_SIZE]; + + const char *entropyfile; + + /* parameters */ + COUNTER Pt[2]; + COUNTER Pg; + int slow_k_of_n; + + /* current thresholds */ + int slow_thresh; + int fast_thresh; + int slow_k_of_n_thresh; +} Yarrow_CTX; + +#if defined(WIN32) +# if defined(YARROW_IMPL) +# define YARROW_DLL __declspec(dllexport) +# else +# define YARROW_DLL __declspec(dllimport) +# endif +#else +# define YARROW_DLL +#endif + +YARROW_DLL +int Yarrow_Init( Yarrow_CTX* y, const char *filename ); + +YARROW_DLL +int Yarrow_Poll( Yarrow_CTX *y, unsigned source_id ); + +YARROW_DLL +int Yarrow_Input( Yarrow_CTX* y, unsigned source_id, + const void* sample, + size_t size, size_t entropy_bits ); + +YARROW_DLL +int Yarrow_Status( Yarrow_CTX* y, int *num_sources, unsigned *source_id, + size_t *entropy_bits, size_t *entropy_max ); + +YARROW_DLL +int Yarrow_Output( Yarrow_CTX* y, void* out, size_t size ); + +YARROW_DLL +int Yarrow_New_Source( Yarrow_CTX* y, unsigned* source_id ); + +YARROW_DLL +int Yarrow_Register_Source_Estimator( Yarrow_CTX* y, unsigned source_id, + estimator_fn* fptr ); + +YARROW_DLL +int Yarrow_Stretch( const byte* m, size_t size, byte* out, size_t out_size ); + +YARROW_DLL +int Yarrow_Reseed( Yarrow_CTX* y, int pool ); + +YARROW_DLL +int Yarrow_Gate( Yarrow_CTX* y ); + +YARROW_DLL +int Yarrow_Final( Yarrow_CTX* y ); + +YARROW_DLL +const char* Yarrow_Str_Error( int ); + + +/* portability stuff */ + +#if defined(macintosh) && YARROW_DRIVER && TARGET_CPU_PPC +# define mem_zero(p, n) BlockZero((p), (n)) +# define mem_copy(d, s, n) BlockMoveData((s), (d), (n)) +#else +# define mem_zero(p, n) memset((p), 0, (n)) +# define mem_copy(d, s, n) memcpy((d), (s), (n)) +#endif + +#if !defined(WIN32) +# define min(x, y) ((x) < (y) ? (x) : (y)) +# define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +/* end portability stuff */ + +#ifdef __cplusplus +} +#endif + +#endif /* YARROW_H */ diff --git a/src/lib/crypto/yarrow/yarrow.man b/src/lib/crypto/yarrow/yarrow.man new file mode 100644 index 000000000..a65b4e05c --- /dev/null +++ b/src/lib/crypto/yarrow/yarrow.man @@ -0,0 +1,315 @@ +.rn '' }` +''' $RCSfile$$Revision$$Date$ +''' +''' $Log$ +''' Revision 1.1 2001/11/08 21:51:57 hartmans +''' Add Yarrow from http://www.zeroknowledge.com/. +''' +''' This is version 0.1 of their Yarrow implementation. I have flattened the distribution, +''' copying files in the src directory directly into this directory. +''' +''' Revision 1.1.2.1 2000/08/13 21:11:24 adamb +''' added some more assumptions +''' included yarrow.man derived from yarrow.pod with pod2man +''' +''' +.de Sh +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n(.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +.de Vb +.ft CW +.nf +.ne \\$1 +.. +.de Ve +.ft R + +.fi +.. +''' +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(*W-|\(bv\*(Tr +.ie n \{\ +.ds -- \(*W- +.ds PI pi +.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +''' \*(M", \*(S", \*(N" and \*(T" are the equivalent of +''' \*(L" and \*(R", except that they are used on ".xx" lines, +''' such as .IP and .SH, which do another additional levels of +''' double-quote interpretation +.ds M" """ +.ds S" """ +.ds N" """"" +.ds T" """"" +.ds L' ' +.ds R' ' +.ds M' ' +.ds S' ' +.ds N' ' +.ds T' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds M" `` +.ds S" '' +.ds N" `` +.ds T" '' +.ds L' ` +.ds R' ' +.ds M' ` +.ds S' ' +.ds N' ` +.ds T' ' +.ds PI \(*p +'br\} +.\" If the F register is turned on, we'll generate +.\" index entries out stderr for the following things: +.\" TH Title +.\" SH Header +.\" Sh Subsection +.\" Ip Item +.\" X<> Xref (embedded +.\" Of course, you have to process the output yourself +.\" in some meaninful fashion. +.if \nF \{ +.de IX +.tm Index:\\$1\t\\n%\t"\\$2" +.. +.nr % 0 +.rr F +.\} +.TH YARROW 1 "perl 5.005, patch 03" "13/Aug/2000" "User Contributed Perl Documentation" +.UC +.if n .hy 0 +.if n .na +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.de CQ \" put $1 in typewriter font +.ft CW +'if n "\c +'if t \\&\\$1\c +'if n \\&\\$1\c +'if n \&" +\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 +'.ft R +.. +.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2 +. \" AM - accent mark definitions +.bd B 3 +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds ? ? +. ds ! ! +. ds / +. ds q +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10' +. ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +. ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#] +.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u' +.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u' +.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#] +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +.ds oe o\h'-(\w'o'u*4/10)'e +.ds Oe O\h'-(\w'O'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds v \h'-1'\o'\(aa\(ga' +. ds _ \h'-1'^ +. ds . \h'-1'. +. ds 3 3 +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +. ds oe oe +. ds Oe OE +.\} +.rm #[ #] #H #V #F C +.SH "NAME" +Yarrow_Init, Yarrow_Poll, Yarrow_Input, Yarrow_Status, Yarrow_Output, Yarrow_New_Source, Yarrow_Register_Source_Estimator, Yarrow Final \- cryptographic pseudo-random number generator +.SH "SYNOPSIS" +int \fIYarrow_Init\fR\|(Yarrow_CTX *y, const char *filename); +.PP +int \fIYarrow_New_Source\fR\|(Yarrow_CTX* y, unsigned* source_id); +.PP +int \fIYarrow_Poll\fR\|(Yarrow_CTX *y, unsigned source_id) +.PP +int \fIYarrow_Input\fR\|( Yarrow_CTX* y, unsigned source_id, + const void* sample, size_t size, + size_t entropy_bits); +.PP +int \fIYarrow_Status\fR\|(Yarrow_CTX* y, int *num_sources, + unsigned *source_id, size_t *entropy_bits, + size_t *entropy_max); +.PP +int \fIYarrow_Output\fR\|(Yarrow_CTX* y, void* out, size_t size); +.PP +int \fIYarrow_Register_Source_Estimator\fR\|(Yarrow_CTX* y, + unsigned source_id, + size_t (*estimator)(const void* sample, + size_t size)); +.PP +int \fIYarrow_Final\fR\|(Yarrow_CTX* y); +.SH "DESCRIPTION" +\fIYarrow_Init()\fR initializes a \fBYarrow_CTX\fR structure. \fBfilename\fR can +be NULL, or the path to a seed file that Yarrow will use to store the +PRNG state for use in later sessions. Returns \fBYARROW_OK\fR if the +PRNG is seeded on exit, or \fBYARROW_NOT_SEEDED\fR if the PRNG is not yet +seeded. +.PP +\fIYarrow_New_Source()\fR associates entropy sources such as keyboard input, +mouse movements and other unpredictable events with a +\fBYarrow_CTX\fR. The function assigns a unique number to the new source, +and places it in \fBsource_id\fR. +.PP +\fIYarrow_Poll()\fR gathers entropy from the state of the machine and adds +it to the source \fBsource_id\fR. The source has to be allocated by the +user with Yarrow_New_Source. Returns \fBYARROW_OK\fR if the PRNG is +seeded on exit, or \fBYARROW_NOT_SEEDED\fR if the PRNG is not yet seeded. +.PP +\fIYarrow_Input()\fR is used to add randomness from the source \fBsource_id\fR +to the PRNG. It reads \fBsize\fR bytes at the address \fBsample\fR. An +estimate of the entropy in bits contained in the sample must be +specified as \fBentropy_bits\fR. +.PP +\fIYarrow_Status()\fR returns \fBYARROW_OK\fR if the PRNG has enough entropy to +produce output, and \fBYARROW_NOT_SEEDED\fR if calls to \fIYarrow_Output()\fR +would fail. +.PP +If num_sources is not NULL, the number of entropy sources that still +need to be seeded is returned in \fB*num_sources\fR. +.PP +If source_id is not NULL, the entropy source that is closest to its +threshold is returned in \fB*source_id\fR. \fB*source_id\fR is set to \-1 if +no sources have either reached their threshold or not collected any +entropy yet. +.PP +If not NULL, \fB*entropy_bits\fR is set to the current number of bits for +the source \fB*source_id\fR, and \fB*entropy_max\fR to the threshold. +.PP +\fIYarrow_Output()\fR generates \fBsize\fR bytes of cryptographically strong +pseudo-random output and places them at \fBout\fR. The return value must +always be checked. If an error occurs, the PRNG may produce +predictable data or no output at all. +.PP +\fIYarrow_Register_Source_Estimator()\fR registers an entropy estimator +for \fBsource_id\fR. An entropy estimator is a function that tries to +estimate the entropy in a sample and returns the entropy in bits +in order to detect abnormal situations in which the samples have a very +low entropy. +.PP +\fIYarrow_Final()\fR writes the PRNG state to the seed file and erases it +from memory. +.SH "RETURN VALUES" +All functions return \fBYARROW_OK\fR on success. Error conditions are reported +as follows: +.PP +.Vb 16 +\& YARROW_FAIL generic failure +\& YARROW_NOT_INIT YarrowInit() hasn't been called +\& YARROW_ALREADY_INIT YarrowInit() has already been called +\& YARROW_NO_DRIVER driver doesn't exist +\& YARROW_CANT_OPEN can't open driver +\& YARROW_BAD_SOURCE invalid source id +\& YARROW_TOO_MANY_SOURCES can't create any more source IDs +\& YARROW_BAD_ARG invalid argument +\& YARROW_ACCESS insufficient privileges +\& YARROW_NOMEM out of memory +\& YARROW_NORSRC a resource (apart from memory) is exhausted +\& YARROW_NOT_SEEDED not enough entropy to generate output +\& YARROW_LOCKING locking error +\& YARROW_NO_STATE there is no state to load +\& YARROW_STATE_ERROR error with state load or save +\& YARROW_NOT_IMPL not implemented +.Ve +.SH "AUTHORS" +Yarrow was designed by John Kelsey, Bruce Schneier and Niels Ferguson +of Counterpane Systems. This implementation is (C) 2000 by +Zero-Knowledge Systems Inc. + +.rn }` '' +.IX Title "YARROW 1" +.IX Name "Yarrow_Init, Yarrow_Poll, Yarrow_Input, Yarrow_Status, Yarrow_Output, Yarrow_New_Source, Yarrow_Register_Source_Estimator, Yarrow Final - cryptographic pseudo-random number generator" + +.IX Header "NAME" + +.IX Header "SYNOPSIS" + +.IX Header "DESCRIPTION" + +.IX Header "RETURN VALUES" + +.IX Header "AUTHORS" + diff --git a/src/lib/crypto/yarrow/yarrow.pod b/src/lib/crypto/yarrow/yarrow.pod new file mode 100644 index 000000000..7892ebbe6 --- /dev/null +++ b/src/lib/crypto/yarrow/yarrow.pod @@ -0,0 +1,112 @@ +=pod + +=head1 NAME + +Yarrow_Init, Yarrow_Poll, Yarrow_Input, Yarrow_Status, Yarrow_Output, Yarrow_New_Source, Yarrow_Register_Source_Estimator, Yarrow Final - cryptographic pseudo-random number generator + +=head1 SYNOPSIS + +int Yarrow_Init(Yarrow_CTX *y, const char *filename); + +int Yarrow_New_Source(Yarrow_CTX* y, unsigned* source_id); + +int Yarrow_Poll(Yarrow_CTX *y, unsigned source_id) + +int Yarrow_Input( Yarrow_CTX* y, unsigned source_id, + const void* sample, size_t size, + size_t entropy_bits); + +int Yarrow_Status(Yarrow_CTX* y, int *num_sources, + unsigned *source_id, size_t *entropy_bits, + size_t *entropy_max); + +int Yarrow_Output(Yarrow_CTX* y, void* out, size_t size); + +int Yarrow_Register_Source_Estimator(Yarrow_CTX* y, + unsigned source_id, + size_t (*estimator)(const void* sample, + size_t size)); + +int Yarrow_Final(Yarrow_CTX* y); + +=head1 DESCRIPTION + +Yarrow_Init() initializes a B structure. B can +be NULL, or the path to a seed file that Yarrow will use to store the +PRNG state for use in later sessions. Returns B if the +PRNG is seeded on exit, or B if the PRNG is not yet +seeded. + +Yarrow_New_Source() associates entropy sources such as keyboard input, +mouse movements and other unpredictable events with a +B. The function assigns a unique number to the new source, +and places it in B. + +Yarrow_Poll() gathers entropy from the state of the machine and adds +it to the source B. The source has to be allocated by the +user with Yarrow_New_Source. Returns B if the PRNG is +seeded on exit, or B if the PRNG is not yet seeded. + +Yarrow_Input() is used to add randomness from the source B +to the PRNG. It reads B bytes at the address B. An +estimate of the entropy in bits contained in the sample must be +specified as B. + +Yarrow_Status() returns B if the PRNG has enough entropy to +produce output, and B if calls to Yarrow_Output() +would fail. + +If num_sources is not NULL, the number of entropy sources that still +need to be seeded is returned in B<*num_sources>. + +If source_id is not NULL, the entropy source that is closest to its +threshold is returned in B<*source_id>. B<*source_id> is set to -1 if +no sources have either reached their threshold or not collected any +entropy yet. + +If not NULL, B<*entropy_bits> is set to the current number of bits for +the source B<*source_id>, and B<*entropy_max> to the threshold. + +Yarrow_Output() generates B bytes of cryptographically strong +pseudo-random output and places them at B. The return value must +always be checked. If an error occurs, the PRNG may produce +predictable data or no output at all. + +Yarrow_Register_Source_Estimator() registers an entropy estimator +for B. An entropy estimator is a function that tries to +estimate the entropy in a sample and returns the entropy in bits +in order to detect abnormal situations in which the samples have a very +low entropy. + +Yarrow_Final() writes the PRNG state to the seed file and erases it +from memory. + +=head1 RETURN VALUES + +All functions return B on success. Error conditions are reported +as follows: + + YARROW_FAIL generic failure + YARROW_NOT_INIT YarrowInit() hasn't been called + YARROW_ALREADY_INIT YarrowInit() has already been called + YARROW_NO_DRIVER driver doesn't exist + YARROW_CANT_OPEN can't open driver + YARROW_BAD_SOURCE invalid source id + YARROW_TOO_MANY_SOURCES can't create any more source IDs + YARROW_BAD_ARG invalid argument + YARROW_ACCESS insufficient privileges + YARROW_NOMEM out of memory + YARROW_NORSRC a resource (apart from memory) is exhausted + YARROW_NOT_SEEDED not enough entropy to generate output + YARROW_LOCKING locking error + YARROW_NO_STATE there is no state to load + YARROW_STATE_ERROR error with state load or save + YARROW_NOT_IMPL not implemented + +=head1 AUTHORS + +Yarrow was designed by John Kelsey, Bruce Schneier and Niels Ferguson +of Counterpane Systems. This implementation is (C) 2000 by +Zero-Knowledge Systems Inc. + +=cut diff --git a/src/lib/crypto/yarrow/ycipher.h b/src/lib/crypto/yarrow/ycipher.h new file mode 100644 index 000000000..38c878d69 --- /dev/null +++ b/src/lib/crypto/yarrow/ycipher.h @@ -0,0 +1,134 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YCIPHER_H +#define YCIPHER_H + +/* block cipher interface */ + +/* default to 3DES for yarrow 160 */ + +#if !defined(YARROW_CIPHER_3DES) && !defined(YARROW_CIPHER_BLOWFISH) +# if !defined(YARROW_CIPHER_IDEA) +# define YARROW_CIPHER_3DES +# endif +#endif + +#if defined(YARROW_CIPHER_3DES) + +/* For yarrow160 use 3 key 3DES */ + +#include "openssl/des.h" + +/* first deal with DES */ + +typedef struct { des_key_schedule ks; } DES_CTX; + +#define DES_BLOCK_SIZE DES_KEY_SZ + +#define DES_PARITY_KEY_SIZE DES_KEY_SZ +/* effective key size, sans parity */ +#define DES_KEY_SIZE (DES_PARITY_KEY_SIZE-1) + +/* key schedule needs to stretch 56 bit key to 64 bit key leaving + * slots for parity bits + */ + +#define DES_Init( ctx, key ) \ +do { \ + byte parity_key[ DES_PARITY_KEY_SIZE ]; \ + void* parity_keyp = (void*)parity_key; \ + parity_key[ 0 ] = (key)[ 0 ]; \ + parity_key[ 1 ] = (key)[ 0 ] << 7 | (key)[ 1 ] >> 2; \ + parity_key[ 2 ] = (key)[ 1 ] << 6 | (key)[ 2 ] >> 3; \ + parity_key[ 3 ] = (key)[ 2 ] << 5 | (key)[ 3 ] >> 4; \ + parity_key[ 4 ] = (key)[ 3 ] << 4 | (key)[ 4 ] >> 5; \ + parity_key[ 5 ] = (key)[ 4 ] << 3 | (key)[ 5 ] >> 6; \ + parity_key[ 6 ] = (key)[ 5 ] << 2 | (key)[ 6 ] >> 7; \ + parity_key[ 7 ] = (key)[ 6 ] << 1; \ + des_key_sched( (des_cblock*) parity_keyp, (ctx)->ks ); \ +} while (0) + +typedef struct +{ + DES_CTX ks1, ks2, ks3; +} CIPHER_CTX; + +#define CIPHER_BLOCK_SIZE DES_BLOCK_SIZE +#define CIPHER_KEY_SIZE (DES_KEY_SIZE * 3) + +#if defined( YARROW_NO_MATHLIB ) +/* see macros at end for functions evaluated */ +#define POW_CIPHER_KEY_SIZE 72057594037927936.0 +#define POW_CIPHER_BLOCK_SIZE 18446744073709551616.0 +#endif + +#define CIPHER_Init(ctx, key) \ +do { \ + DES_Init( &(ctx)->ks1, key ); \ + DES_Init( &(ctx)->ks2, key+DES_KEY_SIZE ); \ + DES_Init( &(ctx)->ks3, key+2*DES_KEY_SIZE ); \ +} while (0) + +#define CIPHER_Encrypt_Block(ctx, in, out)\ + des_ecb3_encrypt((des_cblock*) in, (des_cblock*) out,\ + (ctx)->ks1.ks, (ctx)->ks2.ks, (ctx)->ks3.ks, 1) + +#elif defined(YARROW_CIPHER_BLOWFISH) + +/* macros to allow blowfish */ + +#include "openssl/blowfish.h" + +typedef struct +{ + BF_KEY ks; +} CIPHER_CTX; + +#define CIPHER_BLOCK_SIZE BF_BLOCK +#define CIPHER_KEY_SIZE 16 + +#if defined( YARROW_NO_MATHLIB ) +/* see macros at end for functions evaluated */ +#define POW_CIPHER_KEY_SIZE 6981463658331.6 +#define POW_CIPHER_BLOCK_SIZE 18446744073709551616.0 +#endif + +#define CIPHER_Init(ctx, key)\ + BF_set_key(&(ctx)->ks, CIPHER_KEY_SIZE, (void*)key) +#define CIPHER_Encrypt_Block(ctx, in, out)\ + BF_ecb_encrypt((void*) in, (void*) out, &(ctx)->ks, 1) + +#elif defined(YARROW_CIPHER_IDEA) + +/* macros to allow IDEA */ + +#include "openssl/idea.h" + +typedef struct +{ + IDEA_KEY_SCHEDULE ks; +} CIPHER_CTX; + +#define CIPHER_BLOCK_SIZE IDEA_BLOCK +#define CIPHER_KEY_SIZE IDEA_KEY_LENGTH + +#if defined( YARROW_NO_MATHLIB ) +/* see macros at end for functions evaluated */ +#define POW_CIPHER_KEY_SIZE 6981463658331.55909006437584655441 +#define POW_CIPHER_BLOCK_SIZE 18446744073709551616.000000 +#endif + +#define CIPHER_Init(ctx, key)\ + idea_set_encrypt_key((void*) key, &(ctx)->ks) + +#define CIPHER_Encrypt_Block(ctx, in, out)\ + idea_ecb_encrypt((void*)in, (void*)out, &(ctx)->ks) + +#endif + +#if !defined( YARROW_NO_MATHLIB ) +#define POW_CIPHER_KEY_SIZE pow(2.0, CIPHER_KEY_SIZE * 8 / 3.0) +#define POW_CIPHER_BLOCK_SIZE pow(2.0, CIPHER_BLOCK_SIZE * 8) +#endif + +#endif /* YCIPHER_H */ diff --git a/src/lib/crypto/yarrow/yexcep.h b/src/lib/crypto/yarrow/yexcep.h new file mode 100644 index 000000000..d27de2d5e --- /dev/null +++ b/src/lib/crypto/yarrow/yexcep.h @@ -0,0 +1,107 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YEXCEP_H +#define YEXCEP_H + +/* yes, macros with gotos in them, but in the interests of + * avoiding repetition of code, and having less error prone + * error handling + * + * EXCEP_DECL - declares the return value and local state variables + * needed by the exception macros + * + * THROW( x ) - set return value to x and goto function cleanup + * section (CATCH: block). In the catch block, THROW + * does not goto catch label to avoid loops, and instead + * falls through to the next statement. + * + * EXCEP_OK - success return value (=1) + * + * EXCEP_FAIL - failure return value (=0), other user exceptions are + * given negative values (<0) + * + * TRY( x ) - if code returns value <= 0 TRY sets return value to + * that value and goes to function cleanup section + * (CATCH: block). In the catch block, TRY does not goto + * the catch label to avoid loops, and instead + * falls through to the next statement. The + * return value is set to the first non success value + * returned by a TRY, unless this is overridden by a THROW. + * + * CATCH: - start of catch block, also switches behavior of + * TRY and THROW to not goto CATCH: inside the catch + * block to avoid loops + * + * EXCEP_RET - return the current return value from the function + * equivlanet to return (EXCEPTION) + * + * EXCEPTION - current return value, is set to EXCEP_OK by EXCEP_DECL + * + * EXCEP_BOOL - convert current return value to EXCEP_OK, or EXCEP_FAIL + * (EXCEP_FAIL is anything other than EXCEP_OK) + * + */ + +/* example usage */ + +/* + * + * #define EXCEP_OK_COMMENT 2 + * #define EXCEP_NULL_PTR -1 + * #define EXCEP_OUT_OF_MEM -2 + * + * int bar( char *c ) + * { + * EXCEP_DECL; + * + * if ( !c ) { THROW( EXCEP_NULL_PTR ); } + * if ( *c == '\0' ) { THROW( EXCEP_FAIL ); ); + * if ( *c == '#' ) { SET( EXCEP_COMMENT ); } + * CATCH: + * EXCEP_RET; + * } + * + * int foo( char *c ) + * { + * EXCEP_DECL; + * int *p = NULL; + * + * if ( !c ) { THROW( EXCEP_NULL_PTR ); } + * TRY( bar( c ) ); + * if ( RETURN == EXCEP_COMMENT ) { print( "comment\n" ); } + * p = strdup( c ); + * if ( !p ) { THROW( EXCEP_OUT_OF_MEM ); } + * + * CATCH: + * if ( p ) { TRY( bar( p ) ); free( p ); } + * THROW( EXCEP_BOOL ); + * if ( EXCEPTION == EXCEP_OK ) { printf( "success\n" ); } + * EXCEP_RET; + * } + * + */ + +#define EXCEP_FAIL 0 +#define EXCEP_OK 1 +#define EXCEP_DECL int _thr = 0, _ret2 = 0, _ret = _ret2+EXCEP_OK + +#define THROW( x ) \ + do { \ + _ret = (x); \ + if( !_thr ) { goto _catch; } \ + } while ( 0 ) + +#define TRY( x ) \ + do { \ + _ret2 = (x); \ + if ( _ret > 0 && _ret2 <= 0 ) { THROW( _ret2 ); } \ + } while ( 0 ) + +#define SET( x ) (_ret = (x)) +#define EXCEP_RET return( _ret ) +#define EXCEPTION _ret +#define RETURN _ret2 +#define CATCH _catch: _thr = 1; if ( 0 ) { goto _foo; } _foo +#define EXCEP_BOOL ( _ret > 0 ? EXCEP_OK : EXCEP_FAIL ) + +#endif diff --git a/src/lib/crypto/yarrow/yhash.h b/src/lib/crypto/yarrow/yhash.h new file mode 100644 index 000000000..9ad6ed7fa --- /dev/null +++ b/src/lib/crypto/yarrow/yhash.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YHASH_H +#define YHASH_H + +/* hash function interface */ + +/* default to SHA1 for yarrow 160 */ + +#if !defined(YARROW_HASH_SHA1) && !defined(YARROW_HASH_MD5) +# define YARROW_HASH_SHA1 +#endif + +#if defined(YARROW_HASH_SHA1) + +/* For yarrow160 use SHA1 */ + +#include "openssl/sha.h" + +#define HASH_CTX SHA_CTX +#define HASH_Init(x) SHA1_Init(x) +#define HASH_Update(x, buf, sz) SHA1_Update(x, (void*)buf, sz) +#define HASH_Final(x, digest) SHA1_Final(digest, x) + +#define HASH_DIGEST_SIZE SHA_DIGEST_LENGTH + +#elif defined(YARROW_HASH_MD5) + +#include "openssl/md5.h" + +#define HASH_CTX MD5_CTX +#define HASH_Init(x) MD5_Init(x) +#define HASH_Update(x, buf, sz) MD5_Update(x, (void*)buf, sz) +#define HASH_Final(x, digest) MD5_Final(digest, x) + +#define HASH_DIGEST_SIZE MD5_DIGEST_LENGTH + +#endif + +#endif /* YHASH_H */ diff --git a/src/lib/crypto/yarrow/ylock.h b/src/lib/crypto/yarrow/ylock.h new file mode 100644 index 000000000..cbfd8dc08 --- /dev/null +++ b/src/lib/crypto/yarrow/ylock.h @@ -0,0 +1,18 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YLOCK_H +#define YLOCK_H + +#include "yarrow.h" + +/* these functions should return: + * + * YARROW_OK on success + * and YARROW_LOCKING on failure + */ + +#include "openssl/crypto.h" +int LOCK( void ) { CRYPTO_w_lock(CRYPTO_LOCK_RAND); return (YARROW_OK); } +int UNLOCK( void ) { CRYPTO_w_unlock(CRYPTO_LOCK_RAND); return (YARROW_OK); } + +#endif /* YLOCK_H */ diff --git a/src/lib/crypto/yarrow/yseed.c b/src/lib/crypto/yarrow/yseed.c new file mode 100644 index 000000000..23935aafe --- /dev/null +++ b/src/lib/crypto/yarrow/yseed.c @@ -0,0 +1,297 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ +/* + * Yarrow - Cryptographic Pseudo-Random Number Generator + * Copyright (c) 2000 Zero-Knowledge Systems, Inc. + * + * See the accompanying LICENSE file for license information. + */ + +#ifdef WIN32 +# ifndef _WIN32_WINNT +# define _WIN32_WINNT 0x0400 /* for wincrypt.h */ +# endif +# include +# include +# include +#endif + +#include "yarrow.h" +#include "yexcep.h" + +#ifdef WIN32 +/* Intel hardware RNG CSP -- available from + * http://developer.intel.com/design/security/rng/redist_license.htm + */ +# define PROV_INTEL_SEC 22 +# define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider" + +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *, LPCTSTR, LPCTSTR, + DWORD, DWORD); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE *); +typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV, DWORD); + +typedef HWND (WINAPI *GETFOREGROUNDWINDOW)(VOID); +typedef BOOL (WINAPI *GETCURSORINFO)(PCURSORINFO); +typedef DWORD (WINAPI *GETQUEUESTATUS)(UINT); + +typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD); +typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, DWORD); +typedef BOOL (WINAPI *HEAP32NEXT)(LPHEAPENTRY32); +typedef BOOL (WINAPI *HEAP32LIST)(HANDLE, LPHEAPLIST32); +typedef BOOL (WINAPI *PROCESS32)(HANDLE, LPPROCESSENTRY32); +typedef BOOL (WINAPI *THREAD32)(HANDLE, LPTHREADENTRY32); +typedef BOOL (WINAPI *MODULE32)(HANDLE, LPMODULEENTRY32); + +#define RAND_add(sample, size, entropy_bytes) \ + Yarrow_Input(y, (source_id), (sample), (size), 8*(entropy_bytes)) + +#include "yarrow.h" + +static void readtimer(Yarrow_CTX *, unsigned); + +int Yarrow_Poll(Yarrow_CTX *y, unsigned source_id) +{ + EXCEP_DECL; + MEMORYSTATUS m; + HCRYPTPROV hProvider = 0; + BYTE buf[64]; + DWORD w; + HWND h; + + HMODULE advapi, kernel, user; + CRYPTACQUIRECONTEXT acquire; + CRYPTGENRANDOM gen; + CRYPTRELEASECONTEXT release; + + /* load functions dynamically - not available on all systems */ + advapi = GetModuleHandle("ADVAPI32.DLL"); + kernel = GetModuleHandle("KERNEL32.DLL"); + user = GetModuleHandle("USER32.DLL"); + + if (advapi) + { + acquire = (CRYPTACQUIRECONTEXT) GetProcAddress(advapi, + "CryptAcquireContextA"); + gen = (CRYPTGENRANDOM) GetProcAddress(advapi, + "CryptGenRandom"); + release = (CRYPTRELEASECONTEXT) GetProcAddress(advapi, + "CryptReleaseContext"); + } + + if (acquire && gen && release) + { + /* poll the CryptoAPI PRNG */ + if (acquire(&hProvider, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + { + if (gen(hProvider, sizeof(buf), buf) != 0) + { + RAND_add(buf, sizeof(buf), 0); +# ifdef DEBUG + printf("randomness from PROV_RSA_FULL\n"); +# endif + } + release(hProvider, 0); + } + + /* poll the Pentium PRG with CryptoAPI */ + if (acquire(&hProvider, 0, INTEL_DEF_PROV, PROV_INTEL_SEC, 0)) + { + if (gen(hProvider, sizeof(buf), buf) != 0) + { + RAND_add(buf, sizeof(buf), 0); +# ifdef DEBUG + printf("randomness from PROV_INTEL_SEC\n"); +# endif + } + release(hProvider, 0); + } + } + + /* timer data */ + readtimer(y, source_id); + + /* memory usage statistics */ + GlobalMemoryStatus(&m); + RAND_add(&m, sizeof(m), 1); + + /* process ID */ + w = GetCurrentProcessId(); + RAND_add(&w, sizeof(w), 0); + + if (user) + { + GETCURSORINFO cursor; + GETFOREGROUNDWINDOW win; + GETQUEUESTATUS queue; + + win = (GETFOREGROUNDWINDOW) GetProcAddress(user, "GetForegroundWindow"); + cursor = (GETCURSORINFO) GetProcAddress(user, "GetCursorInfo"); + queue = (GETQUEUESTATUS) GetProcAddress(user, "GetQueueStatus"); + + if (win) + { + /* window handle */ + h = win(); + RAND_add(&h, sizeof(h), 0); + } + + if (cursor) + { + /* cursor position */ + cursor(buf); + RAND_add(buf, sizeof(buf), 0); + } + + if (queue) + { + /* message queue status */ + w = queue(QS_ALLEVENTS); + RAND_add(&w, sizeof(w), 0); + } + } + + /* Toolhelp32 snapshot: enumerate processes, threads, modules and heap + * http://msdn.microsoft.com/library/psdk/winbase/toolhelp_5pfd.htm + * (Win 9x only, not available on NT) + * + * This seeding method was proposed in Peter Gutmann, Software + * Generation of Practically Strong Random Numbers, + * http://www.cs.auckland.ac.nz/~pgut001/pubs/random2.pdf + * (The assignment of entropy estimates below is arbitrary, but based + * on Peter's analysis the full poll appears to be safe. Additional + * interactive seeding is encouraged.) + */ + + if (kernel) + { + CREATETOOLHELP32SNAPSHOT snap; + HANDLE handle; + + HEAP32FIRST heap_first; + HEAP32NEXT heap_next; + HEAP32LIST heaplist_first, heaplist_next; + PROCESS32 process_first, process_next; + THREAD32 thread_first, thread_next; + MODULE32 module_first, module_next; + + HEAPLIST32 hlist; + HEAPENTRY32 hentry; + PROCESSENTRY32 p; + THREADENTRY32 t; + MODULEENTRY32 m; + + snap = (CREATETOOLHELP32SNAPSHOT) + GetProcAddress(kernel, "CreateToolhelp32Snapshot"); + heap_first = (HEAP32FIRST) GetProcAddress(kernel, "Heap32First"); + heap_next = (HEAP32NEXT) GetProcAddress(kernel, "Heap32Next"); + heaplist_first = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListFirst"); + heaplist_next = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListNext"); + process_first = (PROCESS32) GetProcAddress(kernel, "Process32First"); + process_next = (PROCESS32) GetProcAddress(kernel, "Process32Next"); + thread_first = (THREAD32) GetProcAddress(kernel, "Thread32First"); + thread_next = (THREAD32) GetProcAddress(kernel, "Thread32Next"); + module_first = (MODULE32) GetProcAddress(kernel, "Module32First"); + module_next = (MODULE32) GetProcAddress(kernel, "Module32Next"); + + if (snap && heap_first && heap_next && heaplist_first && + heaplist_next && process_first && process_next && + thread_first && thread_next && module_first && + module_next && (handle = snap(TH32CS_SNAPALL,0)) != NULL) + { + /* heap list and heap walking */ + hlist.dwSize = sizeof(HEAPLIST32); + if (heaplist_first(handle, &hlist)) + do + { + RAND_add(&hlist, hlist.dwSize, 0); + hentry.dwSize = sizeof(HEAPENTRY32); + if (heap_first(&hentry, + hlist.th32ProcessID, + hlist.th32HeapID)) + do + RAND_add(&hentry, + hentry.dwSize, 0); + while (heap_next(&hentry)); + } while (heaplist_next(handle, + &hlist)); + + /* process walking */ + p.dwSize = sizeof(PROCESSENTRY32); + if (process_first(handle, &p)) + do + RAND_add(&p, p.dwSize, 0); + while (process_next(handle, &p)); + + /* thread walking */ + t.dwSize = sizeof(THREADENTRY32); + if (thread_first(handle, &t)) + do + RAND_add(&t, t.dwSize, 0); + while (thread_next(handle, &t)); + + /* module walking */ + m.dwSize = sizeof(MODULEENTRY32); + if (module_first(handle, &m)) + do + RAND_add(&m, m.dwSize, 1); + while (module_next(handle, &m)); + + CloseHandle(handle); + } + } + TRY( Yarrow_Status( y, NULL, NULL, NULL, NULL ) ); + CATCH: + EXCEP_RET; +} + +/* feed timing information to the PRNG */ +static void readtimer(Yarrow_CTX *y, unsigned source_id) +{ + DWORD w, cyclecount; + LARGE_INTEGER l; + static int have_perfc = 1; +#ifndef __GNUC__ + static int have_tsc = 1; + + if (have_tsc) { + __try { + __asm { + rdtsc + mov cyclecount, eax + } + RAND_add(&cyclecount, sizeof(cyclecount), 1); + } __except(EXCEPTION_EXECUTE_HANDLER) { + have_tsc = 0; + } + } +#else +# define have_tsc 0 +#endif + + if (have_perfc) { + if (QueryPerformanceCounter(&l) == 0) + { + have_perfc = 0; + } + else + { + RAND_add(&l, sizeof(l), 0); + } + } + + if (!have_tsc && !have_perfc) { + w = GetTickCount(); + RAND_add(&w, sizeof(w), 0); + } +} + +#else + +int Yarrow_Poll(Yarrow_CTX *y, unsigned source_id) +{ + source_id = source_id; + return Yarrow_Status( y, NULL, NULL, NULL, NULL ); +} + +#endif diff --git a/src/lib/crypto/yarrow/ystate.c b/src/lib/crypto/yarrow/ystate.c new file mode 100644 index 000000000..46034616f --- /dev/null +++ b/src/lib/crypto/yarrow/ystate.c @@ -0,0 +1,109 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ +/* + * Yarrow - Cryptographic Pseudo-Random Number Generator + * Copyright (c) 2000 Zero-Knowledge Systems, Inc. + * + * See the accompanying LICENSE file for license information. + */ + +#include +#include +#if !defined(macintosh) +# include +# include +# include +#endif +#include "yarrow.h" +#include "ystate.h" +#include "yexcep.h" + +#ifdef YARROW_SAVE_STATE + +#if defined(macintosh) && YARROW_DRIVER + +/* Mac OS -- driver environment */ + +# include "YarrowDriverCore.h" + +int STATE_Save(const char *filename, const struct Yarrow_STATE* state) +{ +# pragma unused(filename) + + return (PerformStateWrite(state) ? YARROW_OK : YARROW_STATE_ERROR); +} + +int STATE_Load(const char *filename, struct Yarrow_STATE* state) +{ +# pragma unused(filename) + + return (PerformStateRead(state) ? YARROW_OK : YARROW_STATE_ERROR); +} + +#else + +/* Other platforms */ + +int STATE_Save(const char *filename, const struct Yarrow_STATE* state) +{ + EXCEP_DECL; + FILE* fp = NULL; + +#ifndef WIN32 + int fd = open( filename, O_CREAT | O_RDWR, 0600 ); + if ( fd < 0 ) { THROW( YARROW_STATE_ERROR ); } + fp = fdopen(fd, "wb"); +#endif + if ( !fp ) + { + fp = fopen(filename,"wb"); + } + if ( !fp ) { THROW( YARROW_STATE_ERROR ); } +#ifndef WIN32 + if ( chmod(filename, 0600) != 0 ) { THROW( YARROW_STATE_ERROR ); } +#endif + + if ( fwrite(state, sizeof(*state), 1, fp) != 1 ) + { + THROW( YARROW_STATE_ERROR ); + } + + CATCH: + if ( fp ) + { + if ( fclose(fp) != 0 ) { THROW( YARROW_STATE_ERROR ); } + } + EXCEP_RET; +} + +int STATE_Load(const char *filename, struct Yarrow_STATE* state) +{ + EXCEP_DECL; + FILE* fp; + + fp = fopen(filename, "rb"); + if ( !fp ) + { + if ( errno == ENOENT ) /* file doesn't exist */ + { + THROW( YARROW_NO_STATE ); + } + else /* something else went wrong */ + { + THROW( YARROW_STATE_ERROR ); + } + } + if ( fread(state, sizeof(*state), 1, fp) != 1 ) + { + THROW( YARROW_STATE_ERROR ); + } + + CATCH: + if ( fp ) + { + if ( fclose(fp) != 0 ) { THROW( YARROW_STATE_ERROR ); } + } + EXCEP_RET; +} + +#endif /* platform */ +#endif /* YARROW_SAVE_STATE */ diff --git a/src/lib/crypto/yarrow/ystate.h b/src/lib/crypto/yarrow/ystate.h new file mode 100644 index 000000000..2886ca338 --- /dev/null +++ b/src/lib/crypto/yarrow/ystate.h @@ -0,0 +1,28 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YSTATE_H +#define YSTATE_H + +#ifdef YARROW_SAVE_STATE + +#include "ycipher.h" +#include "ytypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Yarrow_STATE { + byte seed[CIPHER_KEY_SIZE * 2]; /* 2k bits saved to seed file */ +} Yarrow_STATE; + +int STATE_Save( const char *filename, const struct Yarrow_STATE* state ); +int STATE_Load( const char *filename, struct Yarrow_STATE* state ); + +#ifdef __cplusplus +} +#endif + +#endif /* YARROW_SAVE_STATE */ + +#endif /* YSTATE_H */ diff --git a/src/lib/crypto/yarrow/ytest.c b/src/lib/crypto/yarrow/ytest.c new file mode 100644 index 000000000..c60c88c1c --- /dev/null +++ b/src/lib/crypto/yarrow/ytest.c @@ -0,0 +1,389 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ +/* + * Yarrow - Cryptographic Pseudo-Random Number Generator + * Copyright (c) 2000 Zero-Knowledge Systems, Inc. + * + * See the accompanying LICENSE file for license information. + */ + +#include +#include +#include +#include "yarrow.h" +#include "yexcep.h" + +void hex_print( FILE* f, const char* var, void* data, size_t size ); +void dump_yarrow_state( FILE* f, Yarrow_CTX* y ); + +#define YARROW_SEED_FILE "seed" + +static void print_yarrow_status( Yarrow_CTX *y ) +{ + int sid, pool; + Source* source; + + for ( pool = 0; pool < 2; pool++ ) + { + printf( " %s: ", pool == YARROW_SLOW_POOL ? "slow" : "fast" ); + for ( sid = 0; sid < y->num_sources; sid++ ) + { + source = &y->source[ sid ]; + printf( "#%d=%d/%d, ", sid, source->entropy[pool], + pool == YARROW_SLOW_POOL ? + y->slow_thresh : y->fast_thresh ); + } + } + printf( "\n" ); +} + +int yarrow_verbose = 0; +#define VERBOSE( x ) if ( yarrow_verbose ) { x } + +int Instrumented_Yarrow_Input( Yarrow_CTX* y, int sid, void* sample, + size_t size, int entropy ) +{ + int ret; + + VERBOSE( printf( "Yarrow_Input( #%d, %d bits, %s ) = [", sid, entropy, + y->source[sid].pool == + YARROW_SLOW_POOL ? "slow" : "fast" ); ); + ret = Yarrow_Input( y, sid, sample, size, entropy ); + + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + VERBOSE( print_yarrow_status( y ); ); + return (ret); +} + +typedef int (*test_fn)( void ); + +int test_1( void ); +int test_2( void ); +int test_3( void ); +int test_4( void ); + +test_fn test_func[] = +{ + test_1, test_2, test_3, test_4 +}; + +#define num_tests ( sizeof(test_func) / sizeof(test_fn) ) + +int do_test( int t ) +{ + EXCEP_DECL; + int ret; + + printf( "doing test %d ... ", t ); fflush( stdout ); + ret = test_func[ t-1 ](); + VERBOSE( printf( "\ndone test %d ", t ); ); + printf( "[%s]\n", Yarrow_Str_Error( ret ) ); fflush( stdout ); + THROW( ret ); + + CATCH: + THROW( EXCEP_BOOL ); + EXCEP_RET; +} + +int main( int argc, char* argv[] ) +{ + EXCEP_DECL; + int test = 0; + char** argvp; + char* arg; + char* conv_ok = NULL; + int ok = YARROW_OK; + int done_some_tests = 0; + int i; + int ret; + +#if defined(__MWERKS__) && defined(macintosh) + argc = ccommand(&argv); +#endif + + for ( argvp = argv+1, i = 1; i < argc; i++, argvp++ ) + { + arg = *argvp; + if ( arg[0] == '-' ) + { + switch ( arg[1] ) + { + case 'v': yarrow_verbose = 1; continue; + default: fprintf( stderr, "usage: test [-v] [[test] ... ]\n" ); + THROW( YARROW_FAIL ); + } + } + conv_ok = NULL; + test = strtoul( arg, &conv_ok, 10 ); + if ( !conv_ok || test < 1 || test > num_tests ) + { + fprintf( stderr, "usage: test [-v] [[test] ... ]\n" ); + THROW( YARROW_FAIL ); + } + else + { + ret = do_test( test ); + if ( ok ) { ok = ret; } + done_some_tests = 1; + } + } + + if ( !done_some_tests ) + { + for ( i = 1; i <= num_tests; i++ ) + { + ret = do_test( i ); + if ( ok ) { ok = ret; } + } + } + THROW( ok ); + + CATCH: + switch (EXCEPTION) + { + case YARROW_OK: + exit (EXIT_SUCCESS); + default: + exit (EXIT_FAILURE); + } +} + +int test_1( void ) +{ + EXCEP_DECL; + +#if defined(YARROW_HASH_SHA1) + VERBOSE( printf( "\nsha1 test\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#elif defined(YARROW_MD5) + VERBOSE( printf( "\nmd5 test\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#else + VERBOSE( printf( "\nunknown hash function\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#endif + CATCH: + EXCEP_RET; +} + +int test_2( void ) +{ + EXCEP_DECL; + +#if defined(YARROW_CIPHER_3DES) + VERBOSE( printf( "\n3des test\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#elif defined(YARROW_CIPHER_BLOWFISH) + VERBOSE( printf( "\nblowfish test\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#elif defined(YARROW_CIPHER_IDEA) + VERBOSE( printf( "\nidea test\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#else + VERBOSE( printf( "\nunknown encryption function\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#endif + CATCH: + EXCEP_RET; +} + +int test_3( void ) +{ + EXCEP_DECL; + +#if !defined(YARROW_CIPHER_3DES) || !defined(YARROW_HASH_SHA1) + VERBOSE( printf( "\nnot Yarrow-SHA1-3DES (aka Yarrow-160)\n\n" ); ); + THROW( YARROW_NOT_IMPL ); +#endif + + VERBOSE( printf( "\nYarrow_Stretch\n\n" ); ); + THROW( YARROW_NOT_IMPL ); + + CATCH: + EXCEP_RET; +} + +int test_4( void ) +{ + EXCEP_DECL; + Yarrow_CTX yarrow; + int initialized = 0; + unsigned user, mouse, keyboard; + int i, ret; + byte user_sample[ 20 ]; + byte mouse_sample[ 4 ]; + byte keyboard_sample[ 2 ]; + byte random[ 30 ]; + byte junk[ 48 ]; + + memset( user_sample, 3, sizeof( user_sample ) ); + memset( mouse_sample, 1, sizeof( mouse_sample ) ); + memset( keyboard_sample, 2, sizeof( keyboard_sample ) ); + + VERBOSE( printf( "\nGeneral workout test\n\n" ); ) + + VERBOSE( printf( "Yarrow_Init() = [" ); ); + ret = Yarrow_Init( &yarrow, YARROW_SEED_FILE ); + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + + if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED ) { THROW( ret ); } + initialized = 1; + +#if defined( YARROW_DEBUG ) + dump_yarrow_state( stdout, &yarrow ); +#endif + + ret = Yarrow_New_Source( &yarrow, &user ); + VERBOSE( printf( "Yarrow_New_Source() = [%s]\n", + Yarrow_Str_Error( ret ) ); ); + if ( ret != YARROW_OK ) { THROW( ret ); } + + VERBOSE( printf( "Yarrow_Poll( #%d ) = [", user ); ); + ret = Yarrow_Poll( &yarrow, user ); + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + + ret = Yarrow_New_Source( &yarrow, &mouse ); + VERBOSE( printf( "Yarrow_New_Source() = [%s]\n", + Yarrow_Str_Error( ret ) ); ); + if ( ret != YARROW_OK ) { THROW( ret ); } + + ret = Yarrow_New_Source( &yarrow, &keyboard ); + VERBOSE( printf( "Yarrow_New_Source() = [%s]\n", + Yarrow_Str_Error( ret ) ); ); + if ( ret != YARROW_OK ) { THROW( ret ); } + +/* prematurely try to draw output, to check failure when no + * seed file, or state saving turned off + */ + + VERBOSE( printf( "Yarrow_Output( %d ) = [", sizeof( random ) ); ); + ret = Yarrow_Output( &yarrow, random, sizeof( random ) ); + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + +/* do it twice so that we some slow samples + * (first sample goes to fast pool, and then samples alternate) + */ + + for ( i = 0; i < 2; i++ ) + { + TRY( Instrumented_Yarrow_Input( &yarrow, mouse, mouse_sample, + sizeof( mouse_sample ), 2 ) ); + + TRY( Instrumented_Yarrow_Input( &yarrow, keyboard, keyboard_sample, + sizeof( keyboard_sample ), 2 ) ); + + TRY( Instrumented_Yarrow_Input( &yarrow, user, user_sample, + sizeof( user_sample ), 2 ) ); + } + +#if defined( YARROW_DEBUG ) + dump_yarrow_state( stdout, &yarrow ); +#endif + + VERBOSE( printf( "\nInduce user source (#%d) to reach " + "slow threshold\n\n", user ); ); + + /* induce fast reseed */ + + for ( i = 0; i < 7; i++ ) + { + TRY( Instrumented_Yarrow_Input( &yarrow, user, user_sample, + sizeof( user_sample ), + sizeof( user_sample ) * 3 ) ); + } + + VERBOSE( printf( "\nInduce mouse source (#%d) to reach " + "slow threshold reseed\n\n", mouse ); ); + + /* induce slow reseed, by triggering a second source to reach it's + threshold */ + + for ( i = 0; i < 40; i++ ) + { + TRY( Instrumented_Yarrow_Input( &yarrow, mouse, mouse_sample, + sizeof( mouse_sample ), + sizeof( mouse_sample )*2 ) ); + } + + VERBOSE( printf( "\nProduce some output\n\n" ); ); + + for ( i = 0; i < 30; i++ ) + { + VERBOSE( printf( "Yarrow_Output( %d ) = [", sizeof( junk ) ); ); + ret = Yarrow_Output( &yarrow, junk, sizeof( junk ) ); + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + if ( ret != YARROW_OK ) { THROW( ret ); } + } + + memset( junk, 0, sizeof( junk ) ); + + VERBOSE( printf( "\nTrigger some fast and slow reseeds\n\n" ); ); + + for ( i = 0; i < 30; i++ ) + { + /* odd input to a different source so there are some slow reseeds */ + + if ( i % 16 == 0 ) + { + TRY( Instrumented_Yarrow_Input( &yarrow, mouse, junk, + sizeof( junk ), + sizeof( junk ) * 3 ) ); + } + else + { + TRY( Instrumented_Yarrow_Input( &yarrow, user, junk, + sizeof( junk ), + sizeof( junk ) * 3 ) ); + } + } + + VERBOSE( printf( "\nPrint some random output\n\n" ); ); + + VERBOSE( printf( "Yarrow_Output( %d ) = [", sizeof( random ) ); ); + ret = Yarrow_Output( &yarrow, random, sizeof( random ) ); + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + if ( ret != YARROW_OK ) + { + THROW( ret ); + } + else + { + VERBOSE( hex_print( stdout, "random", random, sizeof( random ) ); ); + } + + VERBOSE( printf( "\nClose down Yarrow\n\n" ); ); + + CATCH: + if ( initialized ) + { + VERBOSE( printf( "Yarrow_Final() = [" ); ); + ret = Yarrow_Final( &yarrow ); + VERBOSE( printf( "%s]\n", Yarrow_Str_Error( ret ) ); ); + THROW( ret ); + } + EXCEP_RET; +} + +void hex_print( FILE* f, const char* var, void* data, size_t size ) +{ + const char* conv = "0123456789abcdef"; + size_t i; + char* p = (char*) data; + char c, d; + + fprintf( f, var ); + fprintf( f, " = " ); + for ( i = 0; i < size; i++ ) + { + c = conv[ (p[ i ] >> 4) & 0xf ]; + d = conv[ p[ i ] & 0xf ]; + fprintf( f, "%c%c", c, d ); + } + fprintf( f, "\n" ); +} + +void dump_yarrow_state( FILE* f, Yarrow_CTX* y ) +{ + fprintf( f, "===Yarrow State===\n" ); + hex_print( f, "C", y->C, sizeof( y->C ) ); + hex_print( f, "K", y->K, sizeof( y->K ) ); +} diff --git a/src/lib/crypto/yarrow/ytypes.h b/src/lib/crypto/yarrow/ytypes.h new file mode 100644 index 000000000..dc0809817 --- /dev/null +++ b/src/lib/crypto/yarrow/ytypes.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-file-style: "bsd" -*- */ + +#ifndef YTYPES_H +#define YTYPES_H + +#include +#include +#include + +#ifdef WIN32 +# include +#endif + +#define byte unsigned char + +#define uint8 unsigned char +#define int8 signed char + +#define int16 signed short +#define uint16 unsigned short + +#if (ULONG_MAX > 0xFFFFFFFFUL) +# define int32 signed int +# define uint32 unsigned int +# define int64 signed long +# define uint64 unsigned long +#else +# define int32 signed long +# define uint32 unsigned long +# if defined(__GNUC__) +# define int64 signed long long +# define uint64 unsigned long long +# elif defined(__sgi) +# define int64 __int64_t +# define uint64 __uint64_t +# elif defined(__MWERKS__) +# define int64 signed long long +# define uint64 unsigned long long +# elif defined(WIN32) +# define uint64 unsigned __int64 +# endif +#endif + +#if defined(uint64) +# define COUNTER uint64 +#else +# define COUNTER uint32 +#endif + +#define COUNTER_MAX ((COUNTER)0 - 1) + +#endif /* YTYPES_H */ -- 2.26.2