1/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2 *
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
5 *
6 * The library is free for all purposes without any express
7 * guarantee it works.
8 *
9 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
10 */
11#include "tomcrypt.h"
12
13/**
14  @file yarrow.c
15  Yarrow PRNG, Tom St Denis
16*/
17
18#ifdef YARROW
19
20const struct ltc_prng_descriptor yarrow_desc =
21{
22    "yarrow", 64,
23    &yarrow_start,
24    &yarrow_add_entropy,
25    &yarrow_ready,
26    &yarrow_read,
27    &yarrow_done,
28    &yarrow_export,
29    &yarrow_import,
30    &yarrow_test
31};
32
33/**
34  Start the PRNG
35  @param prng     [out] The PRNG state to initialize
36  @return CRYPT_OK if successful
37*/
38int yarrow_start(prng_state *prng)
39{
40   int err;
41
42   LTC_ARGCHK(prng != NULL);
43
44   /* these are the default hash/cipher combo used */
45#ifdef RIJNDAEL
46#if    YARROW_AES==0
47   prng->yarrow.cipher = register_cipher(&rijndael_enc_desc);
48#elif  YARROW_AES==1
49   prng->yarrow.cipher = register_cipher(&aes_enc_desc);
50#elif  YARROW_AES==2
51   prng->yarrow.cipher = register_cipher(&rijndael_desc);
52#elif  YARROW_AES==3
53   prng->yarrow.cipher = register_cipher(&aes_desc);
54#endif
55#elif defined(BLOWFISH)
56   prng->yarrow.cipher = register_cipher(&blowfish_desc);
57#elif defined(TWOFISH)
58   prng->yarrow.cipher = register_cipher(&twofish_desc);
59#elif defined(RC6)
60   prng->yarrow.cipher = register_cipher(&rc6_desc);
61#elif defined(RC5)
62   prng->yarrow.cipher = register_cipher(&rc5_desc);
63#elif defined(SAFERP)
64   prng->yarrow.cipher = register_cipher(&saferp_desc);
65#elif defined(RC2)
66   prng->yarrow.cipher = register_cipher(&rc2_desc);
67#elif defined(NOEKEON)
68   prng->yarrow.cipher = register_cipher(&noekeon_desc);
69#elif defined(ANUBIS)
70   prng->yarrow.cipher = register_cipher(&anubis_desc);
71#elif defined(KSEED)
72   prng->yarrow.cipher = register_cipher(&kseed_desc);
73#elif defined(KHAZAD)
74   prng->yarrow.cipher = register_cipher(&khazad_desc);
75#elif defined(CAST5)
76   prng->yarrow.cipher = register_cipher(&cast5_desc);
77#elif defined(XTEA)
78   prng->yarrow.cipher = register_cipher(&xtea_desc);
79#elif defined(SAFER)
80   prng->yarrow.cipher = register_cipher(&safer_sk128_desc);
81#elif defined(DES)
82   prng->yarrow.cipher = register_cipher(&des3_desc);
83#else
84   #error YARROW needs at least one CIPHER
85#endif
86   if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) {
87      return err;
88   }
89
90#ifdef SHA256
91   prng->yarrow.hash   = register_hash(&sha256_desc);
92#elif defined(SHA512)
93   prng->yarrow.hash   = register_hash(&sha512_desc);
94#elif defined(TIGER)
95   prng->yarrow.hash   = register_hash(&tiger_desc);
96#elif defined(SHA1)
97   prng->yarrow.hash   = register_hash(&sha1_desc);
98#elif defined(RIPEMD320)
99   prng->yarrow.hash   = register_hash(&rmd320_desc);
100#elif defined(RIPEMD256)
101   prng->yarrow.hash   = register_hash(&rmd256_desc);
102#elif defined(RIPEMD160)
103   prng->yarrow.hash   = register_hash(&rmd160_desc);
104#elif defined(RIPEMD128)
105   prng->yarrow.hash   = register_hash(&rmd128_desc);
106#elif defined(MD5)
107   prng->yarrow.hash   = register_hash(&md5_desc);
108#elif defined(MD4)
109   prng->yarrow.hash   = register_hash(&md4_desc);
110#elif defined(MD2)
111   prng->yarrow.hash   = register_hash(&md2_desc);
112#elif defined(WHIRLPOOL)
113   prng->yarrow.hash   = register_hash(&whirlpool_desc);
114#else
115   #error YARROW needs at least one HASH
116#endif
117   if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
118      return err;
119   }
120
121   /* zero the memory used */
122   zeromem(prng->yarrow.pool, sizeof(prng->yarrow.pool));
123   LTC_MUTEX_INIT(&prng->yarrow.prng_lock)
124
125   return CRYPT_OK;
126}
127
128/**
129  Add entropy to the PRNG state
130  @param in       The data to add
131  @param inlen    Length of the data to add
132  @param prng     PRNG state to update
133  @return CRYPT_OK if successful
134*/
135int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
136{
137   hash_state md;
138   int err;
139
140   LTC_ARGCHK(in  != NULL);
141   LTC_ARGCHK(prng != NULL);
142
143   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);
144
145   if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
146      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
147      return err;
148   }
149
150   /* start the hash */
151   if ((err = hash_descriptor[prng->yarrow.hash].init(&md)) != CRYPT_OK) {
152      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
153      return err;
154   }
155
156   /* hash the current pool */
157   if ((err = hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool,
158                                                        hash_descriptor[prng->yarrow.hash].hashsize)) != CRYPT_OK) {
159      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
160      return err;
161   }
162
163   /* add the new entropy */
164   if ((err = hash_descriptor[prng->yarrow.hash].process(&md, in, inlen)) != CRYPT_OK) {
165      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
166      return err;
167   }
168
169   /* store result */
170   if ((err = hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool)) != CRYPT_OK) {
171      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
172      return err;
173   }
174
175   LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
176   return CRYPT_OK;
177}
178
179/**
180  Make the PRNG ready to read from
181  @param prng   The PRNG to make active
182  @return CRYPT_OK if successful
183*/
184int yarrow_ready(prng_state *prng)
185{
186   int ks, err;
187
188   LTC_ARGCHK(prng != NULL);
189   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);
190
191   if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
192      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
193      return err;
194   }
195
196   if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) {
197      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
198      return err;
199   }
200
201   /* setup CTR mode using the "pool" as the key */
202   ks = (int)hash_descriptor[prng->yarrow.hash].hashsize;
203   if ((err = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) {
204      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
205      return err;
206   }
207
208   if ((err = ctr_start(prng->yarrow.cipher,     /* what cipher to use */
209                        prng->yarrow.pool,       /* IV */
210                        prng->yarrow.pool, ks,   /* KEY and key size */
211                        0,                       /* number of rounds */
212                        CTR_COUNTER_LITTLE_ENDIAN, /* little endian counter */
213                        &prng->yarrow.ctr)) != CRYPT_OK) {
214      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
215      return err;
216   }
217   LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
218   return CRYPT_OK;
219}
220
221/**
222  Read from the PRNG
223  @param out      Destination
224  @param outlen   Length of output
225  @param prng     The active PRNG to read from
226  @return Number of octets read
227*/
228unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng)
229{
230   LTC_ARGCHK(out  != NULL);
231   LTC_ARGCHK(prng != NULL);
232
233   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);
234
235   /* put out in predictable state first */
236   zeromem(out, outlen);
237
238   /* now randomize it */
239   if (ctr_encrypt(out, out, outlen, &prng->yarrow.ctr) != CRYPT_OK) {
240      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
241      return 0;
242   }
243   LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
244   return outlen;
245}
246
247/**
248  Terminate the PRNG
249  @param prng   The PRNG to terminate
250  @return CRYPT_OK if successful
251*/
252int yarrow_done(prng_state *prng)
253{
254   int err;
255   LTC_ARGCHK(prng != NULL);
256
257   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);
258
259   /* call cipher done when we invent one ;-) */
260
261   /* we invented one */
262   err = ctr_done(&prng->yarrow.ctr);
263
264   LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
265   return err;
266}
267
268/**
269  Export the PRNG state
270  @param out       [out] Destination
271  @param outlen    [in/out] Max size and resulting size of the state
272  @param prng      The PRNG to export
273  @return CRYPT_OK if successful
274*/
275int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
276{
277   LTC_ARGCHK(out    != NULL);
278   LTC_ARGCHK(outlen != NULL);
279   LTC_ARGCHK(prng   != NULL);
280
281   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);
282
283   /* we'll write 64 bytes for s&g's */
284   if (*outlen < 64) {
285      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
286      *outlen = 64;
287      return CRYPT_BUFFER_OVERFLOW;
288   }
289
290   if (yarrow_read(out, 64, prng) != 64) {
291      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
292      return CRYPT_ERROR_READPRNG;
293   }
294   *outlen = 64;
295
296   return CRYPT_OK;
297}
298
299/**
300  Import a PRNG state
301  @param in       The PRNG state
302  @param inlen    Size of the state
303  @param prng     The PRNG to import
304  @return CRYPT_OK if successful
305*/
306int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
307{
308   int err;
309
310   LTC_ARGCHK(in   != NULL);
311   LTC_ARGCHK(prng != NULL);
312
313   LTC_MUTEX_LOCK(&prng->yarrow.prng_lock);
314
315   if (inlen != 64) {
316      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
317      return CRYPT_INVALID_ARG;
318   }
319
320   if ((err = yarrow_start(prng)) != CRYPT_OK) {
321      LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
322      return err;
323   }
324   err = yarrow_add_entropy(in, 64, prng);
325   LTC_MUTEX_UNLOCK(&prng->yarrow.prng_lock);
326   return err;
327}
328
329/**
330  PRNG self-test
331  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
332*/
333int yarrow_test(void)
334{
335#ifndef LTC_TEST
336   return CRYPT_NOP;
337#else
338   int err;
339   prng_state prng;
340
341   if ((err = yarrow_start(&prng)) != CRYPT_OK) {
342      return err;
343   }
344
345   /* now let's test the hash/cipher that was chosen */
346   if ((err = cipher_descriptor[prng.yarrow.cipher].test()) != CRYPT_OK) {
347      return err;
348   }
349   if ((err = hash_descriptor[prng.yarrow.hash].test()) != CRYPT_OK) {
350      return err;
351   }
352
353   return CRYPT_OK;
354#endif
355}
356
357#endif
358
359
360/* $Source: /cvs/libtom/libtomcrypt/src/prngs/yarrow.c,v $ */
361/* $Revision: 1.10 $ */
362/* $Date: 2006/11/14 04:21:17 $ */
363