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 rc4.c 15 RC4 PRNG, Tom St Denis 16*/ 17 18#ifdef RC4 19 20const struct ltc_prng_descriptor rc4_desc = 21{ 22 "rc4", 32, 23 &rc4_start, 24 &rc4_add_entropy, 25 &rc4_ready, 26 &rc4_read, 27 &rc4_done, 28 &rc4_export, 29 &rc4_import, 30 &rc4_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 rc4_start(prng_state *prng) 39{ 40 LTC_ARGCHK(prng != NULL); 41 42 /* set keysize to zero */ 43 prng->rc4.x = 0; 44 45 return CRYPT_OK; 46} 47 48/** 49 Add entropy to the PRNG state 50 @param in The data to add 51 @param inlen Length of the data to add 52 @param prng PRNG state to update 53 @return CRYPT_OK if successful 54*/ 55int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) 56{ 57 LTC_ARGCHK(in != NULL); 58 LTC_ARGCHK(prng != NULL); 59 60 /* trim as required */ 61 if (prng->rc4.x + inlen > 256) { 62 if (prng->rc4.x == 256) { 63 /* I can't possibly accept another byte, ok maybe a mint wafer... */ 64 return CRYPT_OK; 65 } else { 66 /* only accept part of it */ 67 inlen = 256 - prng->rc4.x; 68 } 69 } 70 71 while (inlen--) { 72 prng->rc4.buf[prng->rc4.x++] = *in++; 73 } 74 75 return CRYPT_OK; 76 77} 78 79/** 80 Make the PRNG ready to read from 81 @param prng The PRNG to make active 82 @return CRYPT_OK if successful 83*/ 84int rc4_ready(prng_state *prng) 85{ 86 unsigned char key[256], tmp, *s; 87 int keylen, x, y, j; 88 89 LTC_ARGCHK(prng != NULL); 90 91 /* extract the key */ 92 s = prng->rc4.buf; 93 XMEMCPY(key, s, 256); 94 keylen = prng->rc4.x; 95 96 /* make RC4 perm and shuffle */ 97 for (x = 0; x < 256; x++) { 98 s[x] = x; 99 } 100 101 for (j = x = y = 0; x < 256; x++) { 102 y = (y + prng->rc4.buf[x] + key[j++]) & 255; 103 if (j == keylen) { 104 j = 0; 105 } 106 tmp = s[x]; s[x] = s[y]; s[y] = tmp; 107 } 108 prng->rc4.x = 0; 109 prng->rc4.y = 0; 110 111#ifdef LTC_CLEAN_STACK 112 zeromem(key, sizeof(key)); 113#endif 114 115 return CRYPT_OK; 116} 117 118/** 119 Read from the PRNG 120 @param out Destination 121 @param outlen Length of output 122 @param prng The active PRNG to read from 123 @return Number of octets read 124*/ 125unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng) 126{ 127 unsigned char x, y, *s, tmp; 128 unsigned long n; 129 130 LTC_ARGCHK(out != NULL); 131 LTC_ARGCHK(prng != NULL); 132 133#ifdef LTC_VALGRIND 134 zeromem(out, outlen); 135#endif 136 137 n = outlen; 138 x = prng->rc4.x; 139 y = prng->rc4.y; 140 s = prng->rc4.buf; 141 while (outlen--) { 142 x = (x + 1) & 255; 143 y = (y + s[x]) & 255; 144 tmp = s[x]; s[x] = s[y]; s[y] = tmp; 145 tmp = (s[x] + s[y]) & 255; 146 *out++ ^= s[tmp]; 147 } 148 prng->rc4.x = x; 149 prng->rc4.y = y; 150 return n; 151} 152 153/** 154 Terminate the PRNG 155 @param prng The PRNG to terminate 156 @return CRYPT_OK if successful 157*/ 158int rc4_done(prng_state *prng) 159{ 160 LTC_ARGCHK(prng != NULL); 161 return CRYPT_OK; 162} 163 164/** 165 Export the PRNG state 166 @param out [out] Destination 167 @param outlen [in/out] Max size and resulting size of the state 168 @param prng The PRNG to export 169 @return CRYPT_OK if successful 170*/ 171int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) 172{ 173 LTC_ARGCHK(outlen != NULL); 174 LTC_ARGCHK(out != NULL); 175 LTC_ARGCHK(prng != NULL); 176 177 if (*outlen < 32) { 178 *outlen = 32; 179 return CRYPT_BUFFER_OVERFLOW; 180 } 181 182 if (rc4_read(out, 32, prng) != 32) { 183 return CRYPT_ERROR_READPRNG; 184 } 185 *outlen = 32; 186 187 return CRYPT_OK; 188} 189 190/** 191 Import a PRNG state 192 @param in The PRNG state 193 @param inlen Size of the state 194 @param prng The PRNG to import 195 @return CRYPT_OK if successful 196*/ 197int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) 198{ 199 int err; 200 LTC_ARGCHK(in != NULL); 201 LTC_ARGCHK(prng != NULL); 202 203 if (inlen != 32) { 204 return CRYPT_INVALID_ARG; 205 } 206 207 if ((err = rc4_start(prng)) != CRYPT_OK) { 208 return err; 209 } 210 return rc4_add_entropy(in, 32, prng); 211} 212 213/** 214 PRNG self-test 215 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled 216*/ 217int rc4_test(void) 218{ 219#if !defined(LTC_TEST) || defined(LTC_VALGRIND) 220 return CRYPT_NOP; 221#else 222 static const struct { 223 unsigned char key[8], pt[8], ct[8]; 224 } tests[] = { 225{ 226 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, 227 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, 228 { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 } 229} 230}; 231 prng_state prng; 232 unsigned char dst[8]; 233 int err, x; 234 235 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { 236 if ((err = rc4_start(&prng)) != CRYPT_OK) { 237 return err; 238 } 239 if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) { 240 return err; 241 } 242 if ((err = rc4_ready(&prng)) != CRYPT_OK) { 243 return err; 244 } 245 XMEMCPY(dst, tests[x].pt, 8); 246 if (rc4_read(dst, 8, &prng) != 8) { 247 return CRYPT_ERROR_READPRNG; 248 } 249 rc4_done(&prng); 250 if (XMEMCMP(dst, tests[x].ct, 8)) { 251#if 0 252 int y; 253 printf("\n\nRC4 failed, I got:\n"); 254 for (y = 0; y < 8; y++) printf("%02x ", dst[y]); 255 printf("\n"); 256#endif 257 return CRYPT_FAIL_TESTVECTOR; 258 } 259 } 260 return CRYPT_OK; 261#endif 262} 263 264#endif 265 266 267/* $Source: /cvs/libtom/libtomcrypt/src/prngs/rc4.c,v $ */ 268/* $Revision: 1.9 $ */ 269/* $Date: 2006/11/16 00:32:18 $ */ 270