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 (at) 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 20 const 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 */ 38 int 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 */ 55 int 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 */ 84 int 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 */ 125 unsigned 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 */ 158 int 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 */ 171 int 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 */ 197 int 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 */ 217 int 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