yarrow.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:19k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /* -*- Mode: C; c-file-style: "bsd" -*- */
  2. /*
  3.  * Yarrow - Cryptographic Pseudo-Random Number Generator
  4.  * Copyright (c) 2000 Zero-Knowledge Systems, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software
  7.  * and its documentation for any purpose is hereby granted without fee,
  8.  * provided that the above copyright notice appear in all copies and that
  9.  * both that copyright notice and this permission notice appear in
  10.  * supporting documentation, and that the name of Zero-Knowledge Systems,
  11.  * Inc. not be used in advertising or publicity pertaining to
  12.  * distribution of the software without specific, written prior
  13.  * permission.  Zero-Knowledge Systems, Inc. makes no representations
  14.  * about the suitability of this software for any purpose.  It is
  15.  * provided "as is" without express or implied warranty.
  16.  * 
  17.  * See the accompanying LICENSE file for more information.
  18.  */
  19. #include <string.h>
  20. #include <limits.h>
  21. #if !defined(WIN32)
  22. #   include <unistd.h>
  23. #   if defined(macintosh)
  24. #       include <Memory.h>
  25. #   else
  26. #       include <netinet/in.h>
  27. #   endif
  28. #endif
  29. #if !defined(YARROW_NO_MATHLIB)
  30. #include <math.h>
  31. #endif
  32. #define YARROW_IMPL
  33. #include "yarrow.h"
  34. #include "yhash.h"
  35. #include "ycipher.h"
  36. #include "ylock.h"
  37. #include "ystate.h"
  38. #include "yexcep.h"
  39. #if defined( YARROW_DEBUG ) || defined( YARROW_TRACE )
  40. #   include <stdio.h>
  41. #endif
  42. #if defined( YARROW_TRACE )
  43. extern int yarrow_verbose;
  44. #define TRACE( x ) do { if (yarrow_verbose) { x } } while (0)
  45. #else
  46. #define TRACE( x ) 
  47. #endif
  48. #if defined(macintosh)
  49. #   define make_big_endian32(x) (x)
  50. #else
  51. #   define make_big_endian32(x) htonl(x)
  52. #endif
  53. #if defined( YARROW_DEBUG )
  54. static void hex_print(FILE* f, const char* var, void* data, size_t size);
  55. #endif
  56. static void block_increment( void* block, const int sz );
  57. #if defined( YARROW_SAVE_STATE )
  58. static int Yarrow_Load_State( Yarrow_CTX *y );
  59. static int Yarrow_Save_State( Yarrow_CTX *y );
  60. #endif
  61. static const byte zero_block[CIPHER_BLOCK_SIZE] = { 0, };
  62. static const char* yarrow_str_error[] = {
  63.     "ok",
  64.     "failed",
  65.     "failed: uninitialized",
  66.     "failed: already initialized",
  67.     "failed: no driver",
  68.     "failed: can't open driver",
  69.     "failed: invalid source id",
  70.     "failed: no more source ids available",
  71.     "failed: invalid argument",
  72.     "failed: insufficient privileges",
  73.     "failed: out of memory",
  74.     "failed: resource exhausted",
  75.     "failed: not enough entropy to generate output",
  76.     "failed: locking error",
  77.     "failed: no state to load",
  78.     "failed: state load or save failed",
  79.     "failed: not implemented"
  80. };
  81. /* calculate limits after initialization */
  82. static void Yarrow_Init_Limits(Yarrow_CTX* y)
  83. {
  84.     double tmp1, tmp2, limit;
  85.     /* max number of gates between reseeds -> exceed this, do forced reseed */
  86.     /* #oututs <= min(2^n, 2^(k/3).Pg) */
  87.     /* => #gates <= min(2^n/Pg, 2^(k/3)) */
  88.     tmp1 = POW_CIPHER_BLOCK_SIZE / y->Pg;
  89.     tmp2 = POW_CIPHER_KEY_SIZE;
  90.     limit = min(tmp1, tmp2);
  91.     if (limit < COUNTER_MAX)
  92.     {
  93. y->gates_limit = limit;
  94.     }
  95.     else
  96.     {
  97. y->gates_limit = COUNTER_MAX;
  98.     }
  99. }
  100. /* if the program was forked, the child must not operate on the same
  101.    PRNG state */
  102. #ifdef YARROW_DETECT_FORK
  103. static int Yarrow_detect_fork(Yarrow_CTX *y)
  104. {
  105.     EXCEP_DECL;
  106.     /* this does not work for multi-threaded apps if threads have different
  107.      * pids */
  108.     if ( y->pid != getpid() )
  109.     {
  110. TRY( Yarrow_Init( y, y->entropyfile ) );
  111.     }
  112.  CATCH:
  113.     EXCEP_RET;
  114. }
  115. #else
  116. #define Yarrow_detect_fork(x) (YARROW_OK)
  117. #endif
  118. static void Yarrow_Make_Seeded( Yarrow_CTX* y )
  119. {
  120.     TRACE( printf( "SEEDED," ); );
  121.     y->seeded = 1;
  122.     /* now we are seeded switch to _THRESH values */
  123.     y->slow_thresh = YARROW_SLOW_THRESH;
  124.     y->fast_thresh = YARROW_FAST_THRESH;
  125.     y->slow_k_of_n_thresh = YARROW_K_OF_N_THRESH;
  126. }
  127. YARROW_DLL
  128. int Yarrow_Init(Yarrow_CTX* y, const char *filename)
  129. {
  130.     EXCEP_DECL;
  131.     int locked = 0;
  132.     if (!y) { THROW( YARROW_BAD_ARG ); }
  133.     TRY( LOCK() );
  134.     locked = 1;
  135.     y->seeded = 0;
  136.     y->saved = 0;
  137. #if defined( YARROW_DETECT_FORK )
  138.     y->pid = getpid();
  139. #endif
  140.     y->entropyfile = filename;
  141.     y->num_sources = 0;
  142.     mem_zero(y->C, sizeof(y->C));
  143.     HASH_Init(&y->pool[YARROW_FAST_POOL]);
  144.     HASH_Init(&y->pool[YARROW_SLOW_POOL]);
  145.     mem_zero(y->K, sizeof(y->K));
  146.     CIPHER_Init(&y->cipher, y->K);
  147.     y->out_left = 0;
  148.     y->out_count = 0;
  149.     y->gate_count = 0;
  150.     y->Pg = YARROW_OUTPUTS_PER_GATE;
  151.     y->Pt[YARROW_FAST_POOL] = YARROW_FAST_PT;
  152.     y->Pt[YARROW_SLOW_POOL] = YARROW_SLOW_PT;
  153.     y->slow_k_of_n = 0;
  154.     /* start with INIT_THRESH values, after seeded, switch to THRESH values */
  155.     y->slow_thresh = YARROW_SLOW_INIT_THRESH;
  156.     y->fast_thresh = YARROW_FAST_INIT_THRESH;
  157.     y->slow_k_of_n_thresh = YARROW_K_OF_N_INIT_THRESH;
  158.     Yarrow_Init_Limits(y);
  159. #if defined( YARROW_SAVE_STATE )
  160.     if ( y->entropyfile != NULL )
  161.     {
  162. int ret = Yarrow_Load_State( y );
  163. if ( ret != YARROW_OK && ret != YARROW_NO_STATE )
  164. {
  165.     THROW( ret );
  166. }
  167. /*  if load suceeded then write new state back immediately
  168.  */
  169. /*  Also check that it's not already saved, because the reseed in
  170.  *  Yarrow_Load_State may trigger a save
  171.  */
  172. if ( ret == YARROW_OK && !y->saved )
  173. {
  174.     TRY( Yarrow_Save_State( y ) );
  175. }
  176.     }
  177. #endif
  178.     if ( !y->seeded )
  179.     {
  180. THROW( YARROW_NOT_SEEDED );
  181.     }
  182.  CATCH:
  183.     if ( locked ) { TRY( UNLOCK() ); }
  184.     EXCEP_RET;
  185. }
  186. YARROW_DLL
  187. int Yarrow_Input( Yarrow_CTX* y, unsigned source_id, 
  188.   const void* sample, 
  189.   size_t size, size_t entropy_bits )
  190. {
  191.     EXCEP_DECL;
  192.     int ret;
  193.     int locked = 0;
  194.     Source* source;
  195.     size_t new_entropy;
  196.     size_t estimate;
  197.     if (!y) { THROW( YARROW_BAD_ARG ); }
  198.     TRY( Yarrow_detect_fork( y ) );
  199.     if (source_id >= y->num_sources) { THROW( YARROW_BAD_SOURCE ); }
  200.   
  201.     source = &y->source[source_id];
  202.   
  203.     if(source->pool != YARROW_FAST_POOL && source->pool != YARROW_SLOW_POOL)
  204.     {
  205. THROW( YARROW_BAD_SOURCE );
  206.     }
  207.     TRY( LOCK() );
  208.     locked = 1;
  209.     /* hash in the sample */
  210.     HASH_Update(&y->pool[source->pool], (const void*)sample, size);
  211.   
  212.     /* only update entropy estimate if pool is not full */
  213.     if ( (source->pool == YARROW_FAST_POOL && 
  214.   source->entropy[source->pool] < y->fast_thresh) ||
  215.  (source->pool == YARROW_SLOW_POOL &&
  216.   source->entropy[source->pool] < y->slow_thresh) )
  217.     {
  218. new_entropy = min(entropy_bits, size * 8 * YARROW_ENTROPY_MULTIPLIER);
  219. if (source->estimator)
  220. {
  221.     estimate = source->estimator(sample, size);
  222.     new_entropy = min(new_entropy, estimate);
  223. }
  224. source->entropy[source->pool] += new_entropy;
  225. if ( source->entropy[source->pool] > YARROW_POOL_SIZE )
  226. {
  227.     source->entropy[source->pool] = YARROW_POOL_SIZE;
  228. }
  229. if (source->pool == YARROW_FAST_POOL)
  230. {
  231.     if (source->entropy[YARROW_FAST_POOL] >= y->fast_thresh)
  232.     {
  233. ret = Yarrow_Reseed(y, YARROW_FAST_POOL);
  234. if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED )
  235. {
  236.     THROW( ret );
  237. }
  238.     }
  239. }
  240. else
  241. {
  242.     if (!source->reached_slow_thresh && 
  243. source->entropy[YARROW_SLOW_POOL] >= y->slow_thresh)
  244.     {
  245. source->reached_slow_thresh = 1;
  246. y->slow_k_of_n++;
  247. if (y->slow_k_of_n >= y->slow_k_of_n_thresh)
  248. {
  249.     y->slow_k_of_n = 0;
  250.     ret = Yarrow_Reseed(y, YARROW_SLOW_POOL);
  251.     if ( ret != YARROW_OK && ret != YARROW_NOT_SEEDED )
  252.     {
  253. THROW( ret );
  254.     }
  255. }
  256.     }
  257. }
  258.     }
  259.   
  260.     /* put samples in alternate pools */
  261.     source->pool = (source->pool + 1) % 2;
  262.   
  263.  CATCH:
  264.     if ( locked ) { TRY( UNLOCK() ); }
  265.     EXCEP_RET;
  266. }
  267. YARROW_DLL
  268. int Yarrow_New_Source(Yarrow_CTX* y, unsigned* source_id)
  269. {
  270.     EXCEP_DECL;
  271.     int locked = 0;
  272.     Source* source;
  273.     if (!y) { THROW( YARROW_BAD_ARG ); }
  274.     TRY( LOCK() );
  275.     locked = 1;
  276.     if (y->num_sources + 1 > YARROW_MAX_SOURCES)
  277.     {
  278. THROW( YARROW_TOO_MANY_SOURCES );
  279.     }
  280.     *source_id = y->num_sources;
  281.     source = &y->source[*source_id];
  282.     source->pool = YARROW_FAST_POOL;
  283.     source->entropy[YARROW_FAST_POOL] = 0;
  284.     source->entropy[YARROW_SLOW_POOL] = 0;
  285.     source->reached_slow_thresh = 0;
  286.     source->estimator = 0;
  287.     y->num_sources++;
  288. CATCH:
  289.     if ( locked ) { TRY( UNLOCK() ); }
  290.     EXCEP_RET;
  291. }
  292. int Yarrow_Register_Source_Estimator(Yarrow_CTX* y, unsigned source_id, 
  293.                                      estimator_fn* fptr)
  294. {
  295.     EXCEP_DECL;
  296.     Source* source;
  297.     if (!y) { THROW( YARROW_BAD_ARG ); }
  298.     if (source_id >= y->num_sources) { THROW( YARROW_BAD_SOURCE ); }
  299.     source = &y->source[source_id];
  300.     source->estimator = fptr;
  301.   
  302.  CATCH:
  303.     EXCEP_RET;
  304. }
  305. static int Yarrow_Output_Block( Yarrow_CTX* y, void* out )
  306. {
  307.     EXCEP_DECL;
  308.     if (!y || !out) { THROW( YARROW_BAD_ARG ); }
  309.     TRACE( printf( "OUT," ); );
  310.     /* perform a gate function after Pg outputs */
  311.     y->out_count++;
  312.     if (y->out_count >= y->Pg)
  313.     {
  314. y->out_count = 0;
  315. TRY( Yarrow_Gate( y ) );
  316. /* require new seed after reaching gates_limit */
  317. y->gate_count++;
  318. if ( y->gate_count >= y->gates_limit )
  319. {
  320.     y->gate_count = 0;
  321.     
  322.     /* not defined whether to do slow or fast reseed */ 
  323.     
  324.     TRACE( printf( "OUTPUT LIMIT REACHED," ); );
  325.     TRY( Yarrow_Reseed( y, YARROW_SLOW_POOL ) );
  326. }
  327.     }
  328.   
  329.     /* C <- (C + 1) mod 2^n */
  330.     block_increment( y->C, CIPHER_BLOCK_SIZE );
  331.     /* R <- E_k(C) */
  332.     CIPHER_Encrypt_Block( &y->cipher, y->C, out );
  333. #if defined(YARROW_DEBUG)
  334.     printf("===n");
  335.     hex_print( stdout, "output: C", y->C, CIPHER_BLOCK_SIZE );
  336.     hex_print( stdout, "output: K", y->K, CIPHER_KEY_SIZE );
  337.     hex_print( stdout, "output: O", out, CIPHER_BLOCK_SIZE );
  338. #endif
  339.  CATCH:
  340.     EXCEP_RET;
  341. }
  342. YARROW_DLL
  343. int Yarrow_Status( Yarrow_CTX* y, int *num_sources, unsigned *source_id,
  344.    size_t *entropy_bits, size_t *entropy_max )
  345. {
  346.     EXCEP_DECL;
  347.     int num = y->slow_k_of_n_thresh;
  348.     int source = -1;
  349.     int emax = y->slow_thresh;
  350.     size_t entropy = 0;
  351.     unsigned i;
  352.     if (!y) { THROW( YARROW_BAD_ARG ); }
  353.     TRY( Yarrow_detect_fork( y ) );
  354.     if (num_sources) { *num_sources = num; }
  355.     if (source_id) { *source_id = -1; }
  356.     if (entropy_bits) { *entropy_bits = 0; }
  357.     if (entropy_max) { *entropy_max = emax; }
  358.     if (y->seeded)
  359.     {
  360. if (num_sources) { *num_sources = 0; }
  361. if (entropy_bits) { *entropy_bits = emax; }
  362. THROW( YARROW_OK );
  363.     }
  364.     for (i = 0; i < y->num_sources; i++)
  365.     {
  366. if (y->source[i].entropy[YARROW_SLOW_POOL] >= y->slow_thresh)
  367. {
  368.     num--;
  369. }
  370. else if (y->source[i].entropy[YARROW_SLOW_POOL] > entropy)
  371. {
  372.     source = i;
  373.     entropy = y->source[i].entropy[YARROW_SLOW_POOL];
  374. }
  375.     }
  376.     if (num_sources) { *num_sources = num; }
  377.     if (source_id) { *source_id = source; }
  378.     if (entropy_bits) { *entropy_bits = entropy; }
  379.     THROW( YARROW_NOT_SEEDED );
  380.  CATCH:
  381.     EXCEP_RET;
  382. }
  383. YARROW_DLL
  384. int Yarrow_Output( Yarrow_CTX* y, void* out, size_t size )
  385. {
  386.     EXCEP_DECL;
  387.     int locked = 0;
  388.     size_t left;
  389.     char* outp;
  390.     size_t use;
  391.     if (!y || !out) { THROW( YARROW_BAD_ARG ); }
  392.     TRY( Yarrow_detect_fork( y ) );
  393.     if (!y->seeded) { THROW( YARROW_NOT_SEEDED ); }
  394.     left = size;
  395.     outp = out;
  396.     TRY( LOCK() );
  397.     if (y->out_left > 0)
  398.     {
  399. use = min(left, y->out_left);
  400. mem_copy(outp, y->out + CIPHER_BLOCK_SIZE - y->out_left, use);
  401. left -= use;
  402. y->out_left -= use;
  403. outp += use;
  404.     }
  405.     for ( ; 
  406.   left >= CIPHER_BLOCK_SIZE;
  407.   left -= CIPHER_BLOCK_SIZE, outp += CIPHER_BLOCK_SIZE)
  408.     {
  409. TRY( Yarrow_Output_Block(y, outp) );
  410.     }
  411.     if (left > 0)
  412.     {
  413. TRY( Yarrow_Output_Block(y, y->out) );
  414. mem_copy(outp, y->out, left);
  415. y->out_left = CIPHER_BLOCK_SIZE - left;
  416.     }
  417.  CATCH:
  418.     if ( locked ) { TRY( UNLOCK() ); }
  419.   
  420.     EXCEP_RET;
  421. }
  422. int Yarrow_Gate(Yarrow_CTX* y)
  423. {
  424.     EXCEP_DECL;
  425.     byte new_K[CIPHER_KEY_SIZE];
  426.     if (!y) { THROW( YARROW_BAD_ARG ); }
  427.   
  428.     TRACE( printf( "GATE[" ); );
  429.     /* K <- Next k bits of PRNG output */
  430.     TRY( Yarrow_Output(y, new_K, CIPHER_KEY_SIZE) );
  431.     mem_copy(y->K, new_K, CIPHER_KEY_SIZE);
  432.     /* need to resetup the key schedule as the key has changed */
  433.     CIPHER_Init(&y->cipher, y->K);
  434.  CATCH:
  435.     TRACE( printf( "]," ); );
  436.     mem_zero(new_K, sizeof(new_K));
  437.     EXCEP_RET;
  438. }
  439. #if defined( YARROW_SAVE_STATE )
  440. static int Yarrow_Load_State( Yarrow_CTX *y )
  441. {
  442.     EXCEP_DECL;
  443.     Yarrow_STATE state;
  444.     
  445.     if ( !y ) { THROW( YARROW_BAD_ARG ); }
  446.     if ( y->entropyfile )
  447.     {
  448. TRY( STATE_Load(y->entropyfile, &state) );
  449. TRACE( printf( "LOAD STATE," ); );
  450. #if defined( YARROW_DEBUG )
  451. hex_print( stderr, "state.load", state.seed, sizeof(state.seed));
  452. #endif
  453.     
  454. /* what to do here is not defined by the Yarrow paper */
  455. /* this is a place holder until we get some clarification */
  456.     
  457. HASH_Update( &y->pool[YARROW_FAST_POOL], 
  458.      state.seed, sizeof(state.seed) );
  459. Yarrow_Make_Seeded( y );
  460. TRY( Yarrow_Reseed(y, YARROW_FAST_POOL) );
  461.     }
  462.  CATCH:
  463.     mem_zero(state.seed, sizeof(state.seed));
  464.     EXCEP_RET;
  465. }
  466. static int Yarrow_Save_State( Yarrow_CTX *y )
  467. {
  468.     EXCEP_DECL;
  469.     Yarrow_STATE state;
  470.     
  471.     if ( !y ) { THROW( YARROW_BAD_ARG ); }
  472.     if ( y->entropyfile && y->seeded ) 
  473.     {
  474. TRACE( printf( "SAVE STATE[" ); );
  475. TRY( Yarrow_Output( y, state.seed, sizeof(state.seed) ) );
  476. TRY( STATE_Save(y->entropyfile, &state) );
  477.     }
  478.     y->saved = 1;
  479. # if defined(YARROW_DEBUG)
  480.     hex_print(stdout, "state.save", state.seed, sizeof(state.seed));
  481. # endif
  482.  CATCH:
  483.     TRACE( printf( "]," ); );
  484.     mem_zero(state.seed, sizeof(state.seed));
  485.     EXCEP_RET;
  486. }
  487. #endif
  488. int Yarrow_Reseed(Yarrow_CTX* y, int pool)
  489. {
  490.     EXCEP_DECL;
  491.     HASH_CTX* fast_pool = &y->pool[YARROW_FAST_POOL];
  492.     HASH_CTX* slow_pool = &y->pool[YARROW_SLOW_POOL];
  493.     byte digest[HASH_DIGEST_SIZE];
  494.     HASH_CTX hash;
  495.     byte v_0[HASH_DIGEST_SIZE];
  496.     byte v_i[HASH_DIGEST_SIZE];
  497.     uint32 big_endian_int32;
  498.     COUNTER i;
  499.     if (!y) { THROW( YARROW_BAD_ARG ); }
  500.     if( pool != YARROW_FAST_POOL && pool != YARROW_SLOW_POOL )
  501.     {
  502. THROW( YARROW_BAD_ARG );
  503.     }
  504.   
  505.     TRACE( printf( "%s RESEED,", 
  506.    pool == YARROW_SLOW_POOL ? "SLOW" : "FAST" ); );
  507.     if (pool == YARROW_SLOW_POOL)
  508.     {
  509. /* SLOW RESEED */
  510. /* feed hash of slow pool into the fast pool */
  511. HASH_Final(slow_pool, digest);
  512. /*  Each pool contains the running hash of all inputs fed into it
  513.  *  since it was last used to carry out a reseed -- this implies
  514.  *  that the pool must be reinitialized after a reseed
  515.  */
  516. HASH_Init(slow_pool);    /* reinitialize slow pool */
  517. HASH_Update(fast_pool, digest, sizeof(digest));
  518. if (y->seeded == 0)
  519. {
  520.     Yarrow_Make_Seeded( y );
  521. }
  522.     }
  523.     /* step 1. v_0 <- hash of all inputs into fast pool */
  524.     HASH_Final(fast_pool, v_0);
  525.     HASH_Init(fast_pool);    /* reinitialize fast pool */ 
  526.     /* v_i <- v_0 */
  527.     mem_copy( v_i, v_0, sizeof(v_0) );
  528.     /* step 2. v_i = h(v_{i-1}|v_0|i) for i = 1,..,Pt */
  529.     /* note: this code has to work for Pt = 0 also */
  530.     for ( i = 0; i < y->Pt[pool]; i++ )
  531.     {
  532. HASH_Init(&hash);
  533. HASH_Update(&hash, v_i, sizeof(v_i));
  534. HASH_Update(&hash, v_0, sizeof(v_0));
  535. big_endian_int32 = make_big_endian32(i >> 32); /* MS word */
  536. HASH_Update(&hash, &big_endian_int32, sizeof(uint32));
  537. big_endian_int32 = make_big_endian32(i & 0xFFFFFFFF); /* LS word */
  538. HASH_Update(&hash, &big_endian_int32, sizeof(uint32));
  539. HASH_Final(&hash, v_i);
  540.     }
  541.     /* step3. K = h'(h(v_Pt|K)) */
  542.     /* t = h(v_Pt|K) */
  543.     HASH_Init(&hash);
  544.     HASH_Update(&hash, v_i, sizeof(v_i));
  545.     HASH_Update(&hash, y->K, sizeof(y->K));
  546.     HASH_Final(&hash, v_i);
  547. #if defined(YARROW_DEBUG)
  548.     hex_print(stdout, "old K", y->K, sizeof(y->K));
  549. #endif
  550.     /* K <- h'(t) */
  551.     TRY( Yarrow_Stretch(v_i, HASH_DIGEST_SIZE, y->K, CIPHER_KEY_SIZE) );
  552.     /* need to resetup the key schedule as the key has changed */
  553.     CIPHER_Init(&y->cipher, y->K);
  554. #if defined(YARROW_DEBUG)
  555.     hex_print(stdout, "new K", y->K, sizeof(y->K));
  556. #endif
  557.     /* step 4. C <- E_k(0) */
  558. #if defined(YARROW_DEBUG)
  559.     hex_print(stdout, "old C", y->C, sizeof(y->C));
  560. #endif
  561.     CIPHER_Encrypt_Block(&y->cipher, zero_block, y->C);
  562. #if defined(YARROW_DEBUG)
  563.     hex_print(stdout, "new C", y->C, sizeof(y->C));
  564. #endif
  565.     /* discard part output from previous key */
  566.   
  567.     y->out_left = 0;
  568.     /*   step 5. Reset all entropy estimate accumulators of the entropy
  569.      *   accumulator to zero
  570.      */
  571.     for (i = 0; i < y->num_sources; i++)
  572.     {
  573. y->source[i].entropy[pool] = 0;
  574. if (pool == YARROW_SLOW_POOL)
  575. {
  576.     /*   if this is a slow reseed, reset the fast pool entropy
  577.      *   accumulator also
  578.      */
  579.     y->source[i].entropy[YARROW_FAST_POOL] = 0;
  580.     y->source[i].reached_slow_thresh = 0;
  581. }
  582.     }
  583.     /*  step 7. If a seed file is in use, the next 2k bits of output
  584.      *  are written to the seed file
  585.      */
  586. #if defined( YARROW_SAVE_STATE )
  587.     if ( y->seeded && y->entropyfile )
  588.     {
  589. TRY( Yarrow_Save_State( y ) );
  590.     }
  591. #endif
  592.  CATCH:
  593.     /*   step 6. Wipe the memory of all intermediate values
  594.      *
  595.      */
  596.     mem_zero( digest, sizeof(digest) );
  597.     mem_zero( &hash, sizeof(hash) );
  598.     mem_zero( v_0, sizeof(v_0) );
  599.     mem_zero( v_i, sizeof(v_i) );
  600.     EXCEP_RET;
  601. }
  602. int Yarrow_Stretch(const byte* m, size_t size, byte* out, size_t out_size)
  603. {
  604.     EXCEP_DECL;
  605.     const byte* s_i;
  606.     byte* outp;
  607.     int left, use;
  608.     HASH_CTX hash, save;
  609.     byte digest[HASH_DIGEST_SIZE];
  610.   
  611.     if (m == NULL || size == 0 || out == NULL || out_size == 0)
  612.     {
  613. THROW( YARROW_BAD_ARG );
  614.     }
  615.   
  616.     /* 
  617.      *   s_0 = m
  618.      *   s_1 = h(s_0 | ... | s_{i-1})
  619.      *
  620.      *   h'(m, k) = first k bits of (s_0 | s_1 | ...)
  621.      *
  622.      */
  623.     outp = out;
  624.     left = out_size;
  625.   
  626.     use = min(out_size, size);
  627.     mem_copy(outp, m, use);    /* get k bits or as many as available */
  628.     s_i = (const byte*)m;            /* pointer to s0 = m */
  629.     outp += use;
  630.     left -= use;
  631.     HASH_Init(&hash);
  632.     for ( ;
  633.   left > 0;
  634.   left -= HASH_DIGEST_SIZE)
  635.     {
  636. HASH_Update(&hash, s_i, use);
  637.     
  638. /* have to save hash state to one side as HASH_final changes state */
  639. mem_copy(&save, &hash, sizeof(hash));
  640. HASH_Final(&hash, digest);
  641. use = min(HASH_DIGEST_SIZE, left);
  642. mem_copy(outp, digest, use);
  643. /* put state back for next time */
  644. mem_copy(&hash, &save, sizeof(hash));
  645. s_i = outp;            /* retain pointer to s_i */
  646. outp += use;
  647.     }
  648.   
  649.  CATCH:
  650.     mem_zero(&hash, sizeof(hash));
  651.     mem_zero(digest, sizeof(digest));
  652.     EXCEP_RET;
  653. }
  654. static void block_increment(void* block, const int sz)
  655. {
  656.     byte* b = block;
  657.     int i;
  658.   
  659.     for (i = sz-1; (++b[i]) == 0 && i > 0; i--)
  660.     {
  661. ; /* nothing */
  662.     }
  663. }
  664. YARROW_DLL
  665. int Yarrow_Final(Yarrow_CTX* y)
  666. {
  667.     EXCEP_DECL;
  668.     int locked = 0;
  669.     if (!y) { THROW( YARROW_BAD_ARG ); }
  670.     TRY( Yarrow_detect_fork(y) );
  671.     TRY( LOCK() );
  672.     locked = 1;
  673. #if defined( YARROW_SAVE_STATE )
  674.     if ( y->seeded && y->entropyfile )
  675.     {
  676. TRY( Yarrow_Save_State( y ) );
  677.     }
  678. #endif
  679.  CATCH:
  680.     if ( locked ) { TRY( UNLOCK() ); }
  681.     mem_zero( y, sizeof(Yarrow_CTX) );
  682.     EXCEP_RET;
  683. }
  684. YARROW_DLL
  685. const char* Yarrow_Str_Error( int err )
  686. {
  687.     err = 1-err;
  688.     if ( err < 0 || err >= sizeof( yarrow_str_error ) / sizeof( char* ) )
  689.     {
  690. err = 1-YARROW_FAIL;
  691.     } 
  692.     return yarrow_str_error[ err ];
  693. }
  694. #if defined(YARROW_DEBUG)
  695. static void hex_print(FILE* f, const char* var, void* data, size_t size)
  696. {
  697.     const char* conv = "0123456789abcdef";
  698.     size_t i;
  699.     char* p = (char*) data;
  700.     char c, d;
  701.     fprintf(f, var);
  702.     fprintf(f, " = ");
  703.     for (i = 0; i < size; i++)
  704.     {
  705. c = conv[(p[i] >> 4) & 0xf];
  706. d = conv[p[i] & 0xf];
  707. fprintf(f, "%c%c", c, d);
  708.     }
  709.     fprintf(f, "n");
  710. }
  711. #endif