Add Yarrow from http://www.zeroknowledge.com/
authorSam Hartman <hartmans@mit.edu>
Thu, 8 Nov 2001 21:51:58 +0000 (21:51 +0000)
committerSam Hartman <hartmans@mit.edu>
Thu, 8 Nov 2001 21:51:58 +0000 (21:51 +0000)
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

18 files changed:
src/lib/crypto/yarrow/ASSUMPTIONS [new file with mode: 0644]
src/lib/crypto/yarrow/LICENSE [new file with mode: 0644]
src/lib/crypto/yarrow/Makefile [new file with mode: 0644]
src/lib/crypto/yarrow/README [new file with mode: 0644]
src/lib/crypto/yarrow/TODO [new file with mode: 0644]
src/lib/crypto/yarrow/yarrow.c [new file with mode: 0644]
src/lib/crypto/yarrow/yarrow.h [new file with mode: 0644]
src/lib/crypto/yarrow/yarrow.man [new file with mode: 0644]
src/lib/crypto/yarrow/yarrow.pod [new file with mode: 0644]
src/lib/crypto/yarrow/ycipher.h [new file with mode: 0644]
src/lib/crypto/yarrow/yexcep.h [new file with mode: 0644]
src/lib/crypto/yarrow/yhash.h [new file with mode: 0644]
src/lib/crypto/yarrow/ylock.h [new file with mode: 0644]
src/lib/crypto/yarrow/yseed.c [new file with mode: 0644]
src/lib/crypto/yarrow/ystate.c [new file with mode: 0644]
src/lib/crypto/yarrow/ystate.h [new file with mode: 0644]
src/lib/crypto/yarrow/ytest.c [new file with mode: 0644]
src/lib/crypto/yarrow/ytypes.h [new file with mode: 0644]

diff --git a/src/lib/crypto/yarrow/ASSUMPTIONS b/src/lib/crypto/yarrow/ASSUMPTIONS
new file mode 100644 (file)
index 0000000..3e3c99c
--- /dev/null
@@ -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 (file)
index 0000000..c85475d
--- /dev/null
@@ -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 (file)
index 0000000..2dd8647
--- /dev/null
@@ -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 (file)
index 0000000..3dd4b80
--- /dev/null
@@ -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 (file)
index 0000000..bd133ec
--- /dev/null
@@ -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 (file)
index 0000000..74dc809
--- /dev/null
@@ -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 (file)
index 0000000..dc74a3b
--- /dev/null
@@ -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 (file)
index 0000000..a65b4e0
--- /dev/null
@@ -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 (file)
index 0000000..7892ebb
--- /dev/null
@@ -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 (file)
index 0000000..38c878d
--- /dev/null
@@ -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 (file)
index 0000000..d27de2d
--- /dev/null
@@ -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 (file)
index 0000000..9ad6ed7
--- /dev/null
@@ -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 (file)
index 0000000..cbfd8dc
--- /dev/null
@@ -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 (file)
index 0000000..23935aa
--- /dev/null
@@ -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 (file)
index 0000000..4603461
--- /dev/null
@@ -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 (file)
index 0000000..2886ca3
--- /dev/null
@@ -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 (file)
index 0000000..c60c88c
--- /dev/null
@@ -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 (file)
index 0000000..dc08098
--- /dev/null
@@ -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 */