Home | History | Annotate | Download | only in rc4
      1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      2  * All rights reserved.
      3  *
      4  * This package is an SSL implementation written
      5  * by Eric Young (eay (at) cryptsoft.com).
      6  * The implementation was written so as to conform with Netscapes SSL.
      7  *
      8  * This library is free for commercial and non-commercial use as long as
      9  * the following conditions are aheared to.  The following conditions
     10  * apply to all code found in this distribution, be it the RC4, RSA,
     11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     12  * included with this distribution is covered by the same copyright terms
     13  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     14  *
     15  * Copyright remains Eric Young's, and as such any Copyright notices in
     16  * the code are not to be removed.
     17  * If this package is used in a product, Eric Young should be given attribution
     18  * as the author of the parts of the library used.
     19  * This can be in the form of a textual message at program startup or
     20  * in documentation (online or textual) provided with the package.
     21  *
     22  * Redistribution and use in source and binary forms, with or without
     23  * modification, are permitted provided that the following conditions
     24  * are met:
     25  * 1. Redistributions of source code must retain the copyright
     26  *    notice, this list of conditions and the following disclaimer.
     27  * 2. Redistributions in binary form must reproduce the above copyright
     28  *    notice, this list of conditions and the following disclaimer in the
     29  *    documentation and/or other materials provided with the distribution.
     30  * 3. All advertising materials mentioning features or use of this software
     31  *    must display the following acknowledgement:
     32  *    "This product includes cryptographic software written by
     33  *     Eric Young (eay (at) cryptsoft.com)"
     34  *    The word 'cryptographic' can be left out if the rouines from the library
     35  *    being used are not cryptographic related :-).
     36  * 4. If you include any Windows specific code (or a derivative thereof) from
     37  *    the apps directory (application code) you must include an acknowledgement:
     38  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     39  *
     40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50  * SUCH DAMAGE.
     51  *
     52  * The licence and distribution terms for any publically available version or
     53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     54  * copied and put under another distribution licence
     55  * [including the GNU Public Licence.] */
     56 
     57 #include <openssl/rc4.h>
     58 
     59 #if defined(OPENSSL_NO_ASM) || \
     60     (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
     61 
     62 #if defined(OPENSSL_64_BIT)
     63 #define RC4_CHUNK uint64_t
     64 #elif defined(OPENSSL_32_BIT)
     65 #define RC4_CHUNK uint32_t
     66 #else
     67 #error "Unknown word size"
     68 #endif
     69 
     70 
     71 /* RC4 as implemented from a posting from
     72  * Newsgroups: sci.crypt
     73  * From: sterndark (at) netcom.com (David Sterndark)
     74  * Subject: RC4 Algorithm revealed.
     75  * Message-ID: <sternCvKL4B.Hyy (at) netcom.com>
     76  * Date: Wed, 14 Sep 1994 06:35:31 GMT */
     77 
     78 void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) {
     79   uint32_t *d;
     80   uint32_t x, y, tx, ty;
     81   size_t i;
     82 
     83   x = key->x;
     84   y = key->y;
     85   d = key->data;
     86 
     87 #define RC4_STEP                                                             \
     88   (x = (x + 1) & 0xff, tx = d[x], y = (tx + y) & 0xff, ty = d[y], d[y] = tx, \
     89    d[x] = ty, (RC4_CHUNK)d[(tx + ty) & 0xff])
     90 
     91   if ((((size_t)in & (sizeof(RC4_CHUNK) - 1)) |
     92        ((size_t)out & (sizeof(RC4_CHUNK) - 1))) == 0) {
     93     RC4_CHUNK ichunk, otp;
     94     const union {
     95       long one;
     96       char little;
     97     } is_endian = {1};
     98 
     99     /* I reckon we can afford to implement both endian
    100      * cases and to decide which way to take at run-time
    101      * because the machine code appears to be very compact
    102      * and redundant 1-2KB is perfectly tolerable (i.e.
    103      * in case the compiler fails to eliminate it:-). By
    104      * suggestion from Terrel Larson <terr (at) terralogic.net>
    105      * who also stands for the is_endian union:-)
    106      *
    107      * Special notes.
    108      *
    109      * - is_endian is declared automatic as doing otherwise
    110      *   (declaring static) prevents gcc from eliminating
    111      *   the redundant code;
    112      * - compilers (those I've tried) don't seem to have
    113      *   problems eliminating either the operators guarded
    114      *   by "if (sizeof(RC4_CHUNK)==8)" or the condition
    115      *   expressions themselves so I've got 'em to replace
    116      *   corresponding #ifdefs from the previous version;
    117      * - I chose to let the redundant switch cases when
    118      *   sizeof(RC4_CHUNK)!=8 be (were also #ifdefed
    119      *   before);
    120      * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in
    121      *   [LB]ESHFT guards against "shift is out of range"
    122      *   warnings when sizeof(RC4_CHUNK)!=8
    123      *
    124      *			<appro (at) fy.chalmers.se> */
    125     if (!is_endian.little) { /* BIG-ENDIAN CASE */
    126 #define BESHFT(c) \
    127   (((sizeof(RC4_CHUNK) - (c) - 1) * 8) & (sizeof(RC4_CHUNK) * 8 - 1))
    128       for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) {
    129         ichunk = *(RC4_CHUNK *)in;
    130         otp = RC4_STEP << BESHFT(0);
    131         otp |= RC4_STEP << BESHFT(1);
    132         otp |= RC4_STEP << BESHFT(2);
    133         otp |= RC4_STEP << BESHFT(3);
    134 #if defined(OPENSSL_64_BIT)
    135         otp |= RC4_STEP << BESHFT(4);
    136         otp |= RC4_STEP << BESHFT(5);
    137         otp |= RC4_STEP << BESHFT(6);
    138         otp |= RC4_STEP << BESHFT(7);
    139 #endif
    140         *(RC4_CHUNK *)out = otp ^ ichunk;
    141         in += sizeof(RC4_CHUNK);
    142         out += sizeof(RC4_CHUNK);
    143       }
    144     } else { /* LITTLE-ENDIAN CASE */
    145 #define LESHFT(c) (((c) * 8) & (sizeof(RC4_CHUNK) * 8 - 1))
    146       for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) {
    147         ichunk = *(RC4_CHUNK *)in;
    148         otp = RC4_STEP;
    149         otp |= RC4_STEP << 8;
    150         otp |= RC4_STEP << 16;
    151         otp |= RC4_STEP << 24;
    152 #if defined(OPENSSL_64_BIT)
    153         otp |= RC4_STEP << LESHFT(4);
    154         otp |= RC4_STEP << LESHFT(5);
    155         otp |= RC4_STEP << LESHFT(6);
    156         otp |= RC4_STEP << LESHFT(7);
    157 #endif
    158         *(RC4_CHUNK *)out = otp ^ ichunk;
    159         in += sizeof(RC4_CHUNK);
    160         out += sizeof(RC4_CHUNK);
    161       }
    162     }
    163   }
    164 #define LOOP(in, out)   \
    165   x = ((x + 1) & 0xff); \
    166   tx = d[x];            \
    167   y = (tx + y) & 0xff;  \
    168   d[x] = ty = d[y];     \
    169   d[y] = tx;            \
    170   (out) = d[(tx + ty) & 0xff] ^ (in);
    171 
    172 #ifndef RC4_INDEX
    173 #define RC4_LOOP(a, b, i) LOOP(*((a)++), *((b)++))
    174 #else
    175 #define RC4_LOOP(a, b, i) LOOP(a[i], b[i])
    176 #endif
    177 
    178   i = len >> 3;
    179   if (i) {
    180     for (;;) {
    181       RC4_LOOP(in, out, 0);
    182       RC4_LOOP(in, out, 1);
    183       RC4_LOOP(in, out, 2);
    184       RC4_LOOP(in, out, 3);
    185       RC4_LOOP(in, out, 4);
    186       RC4_LOOP(in, out, 5);
    187       RC4_LOOP(in, out, 6);
    188       RC4_LOOP(in, out, 7);
    189 #ifdef RC4_INDEX
    190       in += 8;
    191       out += 8;
    192 #endif
    193       if (--i == 0) {
    194         break;
    195       }
    196     }
    197   }
    198   i = len & 0x07;
    199   if (i) {
    200     for (;;) {
    201       RC4_LOOP(in, out, 0);
    202       if (--i == 0) {
    203         break;
    204       }
    205       RC4_LOOP(in, out, 1);
    206       if (--i == 0) {
    207         break;
    208       }
    209       RC4_LOOP(in, out, 2);
    210       if (--i == 0) {
    211         break;
    212       }
    213       RC4_LOOP(in, out, 3);
    214       if (--i == 0) {
    215         break;
    216       }
    217       RC4_LOOP(in, out, 4);
    218       if (--i == 0) {
    219         break;
    220       }
    221       RC4_LOOP(in, out, 5);
    222       if (--i == 0) {
    223         break;
    224       }
    225       RC4_LOOP(in, out, 6);
    226       if (--i == 0) {
    227         break;
    228       }
    229     }
    230   }
    231   key->x = x;
    232   key->y = y;
    233 }
    234 
    235 void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) {
    236   uint32_t tmp;
    237   unsigned i, id1, id2;
    238   uint32_t *d;
    239 
    240   d = &rc4key->data[0];
    241   rc4key->x = 0;
    242   rc4key->y = 0;
    243   id1 = id2 = 0;
    244 
    245 #define SK_LOOP(d, n)                    \
    246   {                                      \
    247     tmp = d[(n)];                        \
    248     id2 = (key[id1] + tmp + id2) & 0xff; \
    249     if (++id1 == len)                    \
    250       id1 = 0;                           \
    251     d[(n)] = d[id2];                     \
    252     d[id2] = tmp;                        \
    253   }
    254 
    255   for (i = 0; i < 256; i++) {
    256     d[i] = i;
    257   }
    258   for (i = 0; i < 256; i += 4) {
    259     SK_LOOP(d, i + 0);
    260     SK_LOOP(d, i + 1);
    261     SK_LOOP(d, i + 2);
    262     SK_LOOP(d, i + 3);
    263   }
    264 }
    265 
    266 #else
    267 
    268 /* In this case several functions are provided by asm code. However, one cannot
    269  * control asm symbol visibility with command line flags and such so they are
    270  * always hidden and wrapped by these C functions, which can be so
    271  * controlled. */
    272 
    273 void asm_RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out);
    274 void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) {
    275   asm_RC4(key, len, in, out);
    276 }
    277 
    278 void asm_RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key);
    279 void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) {
    280   asm_RC4_set_key(rc4key, len, key);
    281 }
    282 
    283 #endif  /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */
    284