Home | History | Annotate | Download | only in prngs
      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