summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2001-11-08 21:51:58 +0000
committerSam Hartman <hartmans@mit.edu>2001-11-08 21:51:58 +0000
commitf6194bd50cadcf6bd8606e864334fddc2cfe1bb6 (patch)
treed0c3d8865bd7b041f504d8fc66f4a1d842765646 /src
parentd5b76d7b09f9bbc035239583d892946db284ed96 (diff)
downloadkrb5-f6194bd50cadcf6bd8606e864334fddc2cfe1bb6.tar.gz
krb5-f6194bd50cadcf6bd8606e864334fddc2cfe1bb6.tar.xz
krb5-f6194bd50cadcf6bd8606e864334fddc2cfe1bb6.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/lib/crypto/yarrow/ASSUMPTIONS101
-rw-r--r--src/lib/crypto/yarrow/LICENSE21
-rw-r--r--src/lib/crypto/yarrow/Makefile51
-rw-r--r--src/lib/crypto/yarrow/README94
-rw-r--r--src/lib/crypto/yarrow/TODO9
-rw-r--r--src/lib/crypto/yarrow/yarrow.c868
-rw-r--r--src/lib/crypto/yarrow/yarrow.h199
-rw-r--r--src/lib/crypto/yarrow/yarrow.man315
-rw-r--r--src/lib/crypto/yarrow/yarrow.pod112
-rw-r--r--src/lib/crypto/yarrow/ycipher.h134
-rw-r--r--src/lib/crypto/yarrow/yexcep.h107
-rw-r--r--src/lib/crypto/yarrow/yhash.h40
-rw-r--r--src/lib/crypto/yarrow/ylock.h18
-rw-r--r--src/lib/crypto/yarrow/yseed.c297
-rw-r--r--src/lib/crypto/yarrow/ystate.c109
-rw-r--r--src/lib/crypto/yarrow/ystate.h28
-rw-r--r--src/lib/crypto/yarrow/ytest.c389
-rw-r--r--src/lib/crypto/yarrow/ytypes.h52
18 files changed, 2944 insertions, 0 deletions
diff --git a/src/lib/crypto/yarrow/ASSUMPTIONS b/src/lib/crypto/yarrow/ASSUMPTIONS
new file mode 100644
index 0000000000..3e3c99c495
--- /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 0000000000..c85475d7e1
--- /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 0000000000..2dd8647896
--- /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 0000000000..3dd4b801a2
--- /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 0000000000..bd133ecfd6
--- /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 0000000000..74dc809cbb
--- /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 <string.h>
+#include <limits.h>
+#if !defined(WIN32)
+# include <unistd.h>
+# if defined(macintosh)
+# include <Memory.h>
+# else
+# include <netinet/in.h>
+# endif
+#endif
+#if !defined(YARROW_NO_MATHLIB)
+#include <math.h>
+#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 <stdio.h>
+#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 0000000000..dc74a3ba0d
--- /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 <unistd.h>
+#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 0000000000..a65b4e05c2
--- /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 0000000000..7892ebbe69
--- /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<Yarrow_CTX> structure. B<filename> 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<YARROW_OK> if the
+PRNG is seeded on exit, or B<YARROW_NOT_SEEDED> 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<Yarrow_CTX>. The function assigns a unique number to the new source,
+and places it in B<source_id>.
+
+Yarrow_Poll() gathers entropy from the state of the machine and adds
+it to the source B<source_id>. The source has to be allocated by the
+user with Yarrow_New_Source. Returns B<YARROW_OK> if the PRNG is
+seeded on exit, or B<YARROW_NOT_SEEDED> if the PRNG is not yet seeded.
+
+Yarrow_Input() is used to add randomness from the source B<source_id>
+to the PRNG. It reads B<size> bytes at the address B<sample>. An
+estimate of the entropy in bits contained in the sample must be
+specified as B<entropy_bits>.
+
+Yarrow_Status() returns B<YARROW_OK> if the PRNG has enough entropy to
+produce output, and B<YARROW_NOT_SEEDED> 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<size> bytes of cryptographically strong
+pseudo-random output and places them at B<out>. 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<source_id>. 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<YARROW_OK> 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 0000000000..38c878d69c
--- /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 0000000000..d27de2d5e4
--- /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 0000000000..9ad6ed7fac
--- /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 0000000000..cbfd8dc08c
--- /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 0000000000..23935aafe3
--- /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 <windows.h>
+# include <wincrypt.h>
+# include <tlhelp32.h>
+#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 0000000000..46034616f9
--- /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 <stdio.h>
+#include <errno.h>
+#if !defined(macintosh)
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+#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 0000000000..2886ca3388
--- /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 0000000000..c60c88c1c6
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 0000000000..dc08098179
--- /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 <limits.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+#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 */