1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 
12 /**
13   @file yarrow.c
14   Yarrow PRNG, Tom St Denis
15 */
16 
17 #ifdef LTC_YARROW
18 
19 const struct ltc_prng_descriptor yarrow_desc =
20 {
21     "yarrow", 64,
22     &yarrow_start,
23     &yarrow_add_entropy,
24     &yarrow_ready,
25     &yarrow_read,
26     &yarrow_done,
27     &yarrow_export,
28     &yarrow_import,
29     &yarrow_test
30 };
31 
32 /**
33   Start the PRNG
34   @param prng     [out] The PRNG state to initialize
35   @return CRYPT_OK if successful
36 */
yarrow_start(prng_state * prng)37 int yarrow_start(prng_state *prng)
38 {
39    int err;
40 
41    LTC_ARGCHK(prng != NULL);
42    prng->ready = 0;
43 
44    /* these are the default hash/cipher combo used */
45 #ifdef LTC_RIJNDAEL
46 #if    LTC_YARROW_AES==0
47    prng->u.yarrow.cipher = register_cipher(&rijndael_enc_desc);
48 #elif  LTC_YARROW_AES==1
49    prng->u.yarrow.cipher = register_cipher(&aes_enc_desc);
50 #elif  LTC_YARROW_AES==2
51    prng->u.yarrow.cipher = register_cipher(&rijndael_desc);
52 #elif  LTC_YARROW_AES==3
53    prng->u.yarrow.cipher = register_cipher(&aes_desc);
54 #endif
55 #elif defined(LTC_BLOWFISH)
56    prng->u.yarrow.cipher = register_cipher(&blowfish_desc);
57 #elif defined(LTC_TWOFISH)
58    prng->u.yarrow.cipher = register_cipher(&twofish_desc);
59 #elif defined(LTC_RC6)
60    prng->u.yarrow.cipher = register_cipher(&rc6_desc);
61 #elif defined(LTC_RC5)
62    prng->u.yarrow.cipher = register_cipher(&rc5_desc);
63 #elif defined(LTC_SAFERP)
64    prng->u.yarrow.cipher = register_cipher(&saferp_desc);
65 #elif defined(LTC_RC2)
66    prng->u.yarrow.cipher = register_cipher(&rc2_desc);
67 #elif defined(LTC_NOEKEON)
68    prng->u.yarrow.cipher = register_cipher(&noekeon_desc);
69 #elif defined(LTC_ANUBIS)
70    prng->u.yarrow.cipher = register_cipher(&anubis_desc);
71 #elif defined(LTC_KSEED)
72    prng->u.yarrow.cipher = register_cipher(&kseed_desc);
73 #elif defined(LTC_KHAZAD)
74    prng->u.yarrow.cipher = register_cipher(&khazad_desc);
75 #elif defined(LTC_CAST5)
76    prng->u.yarrow.cipher = register_cipher(&cast5_desc);
77 #elif defined(LTC_XTEA)
78    prng->u.yarrow.cipher = register_cipher(&xtea_desc);
79 #elif defined(LTC_SAFER)
80    prng->u.yarrow.cipher = register_cipher(&safer_sk128_desc);
81 #elif defined(LTC_DES)
82    prng->u.yarrow.cipher = register_cipher(&des3_desc);
83 #else
84    #error LTC_YARROW needs at least one CIPHER
85 #endif
86    if ((err = cipher_is_valid(prng->u.yarrow.cipher)) != CRYPT_OK) {
87       return err;
88    }
89 
90 #ifdef LTC_SHA256
91    prng->u.yarrow.hash   = register_hash(&sha256_desc);
92 #elif defined(LTC_SHA512)
93    prng->u.yarrow.hash   = register_hash(&sha512_desc);
94 #elif defined(LTC_TIGER)
95    prng->u.yarrow.hash   = register_hash(&tiger_desc);
96 #elif defined(LTC_SHA1)
97    prng->u.yarrow.hash   = register_hash(&sha1_desc);
98 #elif defined(LTC_RIPEMD320)
99    prng->u.yarrow.hash   = register_hash(&rmd320_desc);
100 #elif defined(LTC_RIPEMD256)
101    prng->u.yarrow.hash   = register_hash(&rmd256_desc);
102 #elif defined(LTC_RIPEMD160)
103    prng->u.yarrow.hash   = register_hash(&rmd160_desc);
104 #elif defined(LTC_RIPEMD128)
105    prng->u.yarrow.hash   = register_hash(&rmd128_desc);
106 #elif defined(LTC_MD5)
107    prng->u.yarrow.hash   = register_hash(&md5_desc);
108 #elif defined(LTC_MD4)
109    prng->u.yarrow.hash   = register_hash(&md4_desc);
110 #elif defined(LTC_MD2)
111    prng->u.yarrow.hash   = register_hash(&md2_desc);
112 #elif defined(LTC_WHIRLPOOL)
113    prng->u.yarrow.hash   = register_hash(&whirlpool_desc);
114 #else
115    #error LTC_YARROW needs at least one HASH
116 #endif
117    if ((err = hash_is_valid(prng->u.yarrow.hash)) != CRYPT_OK) {
118       return err;
119    }
120 
121    /* zero the memory used */
122    zeromem(prng->u.yarrow.pool, sizeof(prng->u.yarrow.pool));
123    LTC_MUTEX_INIT(&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 */
yarrow_add_entropy(const unsigned char * in,unsigned long inlen,prng_state * prng)135 int 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(prng != NULL);
141    LTC_ARGCHK(in != NULL);
142    LTC_ARGCHK(inlen > 0);
143 
144    LTC_MUTEX_LOCK(&prng->lock);
145 
146    if ((err = hash_is_valid(prng->u.yarrow.hash)) != CRYPT_OK) {
147       goto LBL_UNLOCK;
148    }
149 
150    /* start the hash */
151    if ((err = hash_descriptor[prng->u.yarrow.hash]->init(&md)) != CRYPT_OK) {
152       goto LBL_UNLOCK;
153    }
154 
155    /* hash the current pool */
156    if ((err = hash_descriptor[prng->u.yarrow.hash]->process(&md, prng->u.yarrow.pool,
157                                                         hash_descriptor[prng->u.yarrow.hash]->hashsize)) != CRYPT_OK) {
158       goto LBL_UNLOCK;
159    }
160 
161    /* add the new entropy */
162    if ((err = hash_descriptor[prng->u.yarrow.hash]->process(&md, in, inlen)) != CRYPT_OK) {
163       goto LBL_UNLOCK;
164    }
165 
166    /* store result */
167    err = hash_descriptor[prng->u.yarrow.hash]->done(&md, prng->u.yarrow.pool);
168 
169 LBL_UNLOCK:
170    LTC_MUTEX_UNLOCK(&prng->lock);
171    return err;
172 }
173 
174 /**
175   Make the PRNG ready to read from
176   @param prng   The PRNG to make active
177   @return CRYPT_OK if successful
178 */
yarrow_ready(prng_state * prng)179 int yarrow_ready(prng_state *prng)
180 {
181    int ks, err;
182 
183    LTC_ARGCHK(prng != NULL);
184 
185    LTC_MUTEX_LOCK(&prng->lock);
186 
187    if ((err = hash_is_valid(prng->u.yarrow.hash)) != CRYPT_OK) {
188       goto LBL_UNLOCK;
189    }
190 
191    if ((err = cipher_is_valid(prng->u.yarrow.cipher)) != CRYPT_OK) {
192       goto LBL_UNLOCK;
193    }
194 
195    /* setup CTR mode using the "pool" as the key */
196    ks = (int)hash_descriptor[prng->u.yarrow.hash]->hashsize;
197    if ((err = cipher_descriptor[prng->u.yarrow.cipher]->keysize(&ks)) != CRYPT_OK) {
198       goto LBL_UNLOCK;
199    }
200 
201    if ((err = ctr_start(prng->u.yarrow.cipher,     /* what cipher to use */
202                         prng->u.yarrow.pool,       /* IV */
203                         prng->u.yarrow.pool, ks,   /* KEY and key size */
204                         0,                       /* number of rounds */
205                         CTR_COUNTER_LITTLE_ENDIAN, /* little endian counter */
206                         &prng->u.yarrow.ctr)) != CRYPT_OK) {
207       goto LBL_UNLOCK;
208    }
209    prng->ready = 1;
210 
211 LBL_UNLOCK:
212    LTC_MUTEX_UNLOCK(&prng->lock);
213    return err;
214 }
215 
216 /**
217   Read from the PRNG
218   @param out      Destination
219   @param outlen   Length of output
220   @param prng     The active PRNG to read from
221   @return Number of octets read
222 */
yarrow_read(unsigned char * out,unsigned long outlen,prng_state * prng)223 unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng)
224 {
225    if (outlen == 0 || prng == NULL || out == NULL) return 0;
226 
227    LTC_MUTEX_LOCK(&prng->lock);
228 
229    if (!prng->ready) {
230       outlen = 0;
231       goto LBL_UNLOCK;
232    }
233 
234    /* put out in predictable state first */
235    zeromem(out, outlen);
236 
237    /* now randomize it */
238    if (ctr_encrypt(out, out, outlen, &prng->u.yarrow.ctr) != CRYPT_OK) {
239       outlen = 0;
240    }
241 
242 LBL_UNLOCK:
243    LTC_MUTEX_UNLOCK(&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 */
yarrow_done(prng_state * prng)252 int yarrow_done(prng_state *prng)
253 {
254    int err;
255    LTC_ARGCHK(prng != NULL);
256 
257    LTC_MUTEX_LOCK(&prng->lock);
258    prng->ready = 0;
259 
260    /* call cipher done when we invent one ;-) */
261 
262    /* we invented one */
263    err = ctr_done(&prng->u.yarrow.ctr);
264 
265    LTC_MUTEX_UNLOCK(&prng->lock);
266    LTC_MUTEX_DESTROY(&prng->lock);
267    return err;
268 }
269 
270 /**
271   Export the PRNG state
272   @param out       [out] Destination
273   @param outlen    [in/out] Max size and resulting size of the state
274   @param prng      The PRNG to export
275   @return CRYPT_OK if successful
276 */
_LTC_PRNG_EXPORT(yarrow)277 _LTC_PRNG_EXPORT(yarrow)
278 
279 /**
280   Import a PRNG state
281   @param in       The PRNG state
282   @param inlen    Size of the state
283   @param prng     The PRNG to import
284   @return CRYPT_OK if successful
285 */
286 int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
287 {
288    int err;
289 
290    LTC_ARGCHK(in   != NULL);
291    LTC_ARGCHK(prng != NULL);
292    if (inlen < (unsigned long)yarrow_desc.export_size) return CRYPT_INVALID_ARG;
293 
294    if ((err = yarrow_start(prng)) != CRYPT_OK)                  return err;
295    if ((err = yarrow_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
296    return CRYPT_OK;
297 }
298 
299 /**
300   PRNG self-test
301   @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
302 */
yarrow_test(void)303 int yarrow_test(void)
304 {
305 #ifndef LTC_TEST
306    return CRYPT_NOP;
307 #else
308    int err;
309    prng_state prng;
310 
311    if ((err = yarrow_start(&prng)) != CRYPT_OK) {
312       return err;
313    }
314 
315    /* now let's test the hash/cipher that was chosen */
316    if (cipher_descriptor[prng.u.yarrow.cipher]->test &&
317        ((err = cipher_descriptor[prng.u.yarrow.cipher]->test()) != CRYPT_OK)) {
318       return err;
319    }
320    if (hash_descriptor[prng.u.yarrow.hash]->test &&
321        ((err = hash_descriptor[prng.u.yarrow.hash]->test()) != CRYPT_OK)) {
322       return err;
323    }
324 
325    return CRYPT_OK;
326 #endif
327 }
328 
329 #endif
330 
331 
332 /* ref:         $Format:%D$ */
333 /* git commit:  $Format:%H$ */
334 /* commit time: $Format:%ai$ */
335