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