1*0Sstevel@tonic-gate /* crypto/rc4/rc4_enc.c */ 2*0Sstevel@tonic-gate /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3*0Sstevel@tonic-gate * All rights reserved. 4*0Sstevel@tonic-gate * 5*0Sstevel@tonic-gate * This package is an SSL implementation written 6*0Sstevel@tonic-gate * by Eric Young (eay@cryptsoft.com). 7*0Sstevel@tonic-gate * The implementation was written so as to conform with Netscapes SSL. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * This library is free for commercial and non-commercial use as long as 10*0Sstevel@tonic-gate * the following conditions are aheared to. The following conditions 11*0Sstevel@tonic-gate * apply to all code found in this distribution, be it the RC4, RSA, 12*0Sstevel@tonic-gate * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13*0Sstevel@tonic-gate * included with this distribution is covered by the same copyright terms 14*0Sstevel@tonic-gate * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15*0Sstevel@tonic-gate * 16*0Sstevel@tonic-gate * Copyright remains Eric Young's, and as such any Copyright notices in 17*0Sstevel@tonic-gate * the code are not to be removed. 18*0Sstevel@tonic-gate * If this package is used in a product, Eric Young should be given attribution 19*0Sstevel@tonic-gate * as the author of the parts of the library used. 20*0Sstevel@tonic-gate * This can be in the form of a textual message at program startup or 21*0Sstevel@tonic-gate * in documentation (online or textual) provided with the package. 22*0Sstevel@tonic-gate * 23*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 24*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 25*0Sstevel@tonic-gate * are met: 26*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the copyright 27*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 28*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 29*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 30*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 31*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 32*0Sstevel@tonic-gate * must display the following acknowledgement: 33*0Sstevel@tonic-gate * "This product includes cryptographic software written by 34*0Sstevel@tonic-gate * Eric Young (eay@cryptsoft.com)" 35*0Sstevel@tonic-gate * The word 'cryptographic' can be left out if the rouines from the library 36*0Sstevel@tonic-gate * being used are not cryptographic related :-). 37*0Sstevel@tonic-gate * 4. If you include any Windows specific code (or a derivative thereof) from 38*0Sstevel@tonic-gate * the apps directory (application code) you must include an acknowledgement: 39*0Sstevel@tonic-gate * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40*0Sstevel@tonic-gate * 41*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51*0Sstevel@tonic-gate * SUCH DAMAGE. 52*0Sstevel@tonic-gate * 53*0Sstevel@tonic-gate * The licence and distribution terms for any publically available version or 54*0Sstevel@tonic-gate * derivative of this code cannot be changed. i.e. this code cannot simply be 55*0Sstevel@tonic-gate * copied and put under another distribution licence 56*0Sstevel@tonic-gate * [including the GNU Public Licence.] 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #include <openssl/rc4.h> 60*0Sstevel@tonic-gate #include "rc4_locl.h" 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* RC4 as implemented from a posting from 63*0Sstevel@tonic-gate * Newsgroups: sci.crypt 64*0Sstevel@tonic-gate * From: sterndark@netcom.com (David Sterndark) 65*0Sstevel@tonic-gate * Subject: RC4 Algorithm revealed. 66*0Sstevel@tonic-gate * Message-ID: <sternCvKL4B.Hyy@netcom.com> 67*0Sstevel@tonic-gate * Date: Wed, 14 Sep 1994 06:35:31 GMT 68*0Sstevel@tonic-gate */ 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata, 71*0Sstevel@tonic-gate unsigned char *outdata) 72*0Sstevel@tonic-gate { 73*0Sstevel@tonic-gate register RC4_INT *d; 74*0Sstevel@tonic-gate register RC4_INT x,y,tx,ty; 75*0Sstevel@tonic-gate int i; 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate x=key->x; 78*0Sstevel@tonic-gate y=key->y; 79*0Sstevel@tonic-gate d=key->data; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate #if defined(RC4_CHUNK) 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * The original reason for implementing this(*) was the fact that 84*0Sstevel@tonic-gate * pre-21164a Alpha CPUs don't have byte load/store instructions 85*0Sstevel@tonic-gate * and e.g. a byte store has to be done with 64-bit load, shift, 86*0Sstevel@tonic-gate * and, or and finally 64-bit store. Peaking data and operating 87*0Sstevel@tonic-gate * at natural word size made it possible to reduce amount of 88*0Sstevel@tonic-gate * instructions as well as to perform early read-ahead without 89*0Sstevel@tonic-gate * suffering from RAW (read-after-write) hazard. This resulted 90*0Sstevel@tonic-gate * in ~40%(**) performance improvement on 21064 box with gcc. 91*0Sstevel@tonic-gate * But it's not only Alpha users who win here:-) Thanks to the 92*0Sstevel@tonic-gate * early-n-wide read-ahead this implementation also exhibits 93*0Sstevel@tonic-gate * >40% speed-up on SPARC and 20-30% on 64-bit MIPS (depending 94*0Sstevel@tonic-gate * on sizeof(RC4_INT)). 95*0Sstevel@tonic-gate * 96*0Sstevel@tonic-gate * (*) "this" means code which recognizes the case when input 97*0Sstevel@tonic-gate * and output pointers appear to be aligned at natural CPU 98*0Sstevel@tonic-gate * word boundary 99*0Sstevel@tonic-gate * (**) i.e. according to 'apps/openssl speed rc4' benchmark, 100*0Sstevel@tonic-gate * crypto/rc4/rc4speed.c exhibits almost 70% speed-up... 101*0Sstevel@tonic-gate * 102*0Sstevel@tonic-gate * Cavets. 103*0Sstevel@tonic-gate * 104*0Sstevel@tonic-gate * - RC4_CHUNK="unsigned long long" should be a #1 choice for 105*0Sstevel@tonic-gate * UltraSPARC. Unfortunately gcc generates very slow code 106*0Sstevel@tonic-gate * (2.5-3 times slower than one generated by Sun's WorkShop 107*0Sstevel@tonic-gate * C) and therefore gcc (at least 2.95 and earlier) should 108*0Sstevel@tonic-gate * always be told that RC4_CHUNK="unsigned long". 109*0Sstevel@tonic-gate * 110*0Sstevel@tonic-gate * <appro@fy.chalmers.se> 111*0Sstevel@tonic-gate */ 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate # define RC4_STEP ( \ 114*0Sstevel@tonic-gate x=(x+1) &0xff, \ 115*0Sstevel@tonic-gate tx=d[x], \ 116*0Sstevel@tonic-gate y=(tx+y)&0xff, \ 117*0Sstevel@tonic-gate ty=d[y], \ 118*0Sstevel@tonic-gate d[y]=tx, \ 119*0Sstevel@tonic-gate d[x]=ty, \ 120*0Sstevel@tonic-gate (RC4_CHUNK)d[(tx+ty)&0xff]\ 121*0Sstevel@tonic-gate ) 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate if ( ( ((unsigned long)indata & (sizeof(RC4_CHUNK)-1)) | 124*0Sstevel@tonic-gate ((unsigned long)outdata & (sizeof(RC4_CHUNK)-1)) ) == 0 ) 125*0Sstevel@tonic-gate { 126*0Sstevel@tonic-gate RC4_CHUNK ichunk,otp; 127*0Sstevel@tonic-gate const union { long one; char little; } is_endian = {1}; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate /* 130*0Sstevel@tonic-gate * I reckon we can afford to implement both endian 131*0Sstevel@tonic-gate * cases and to decide which way to take at run-time 132*0Sstevel@tonic-gate * because the machine code appears to be very compact 133*0Sstevel@tonic-gate * and redundant 1-2KB is perfectly tolerable (i.e. 134*0Sstevel@tonic-gate * in case the compiler fails to eliminate it:-). By 135*0Sstevel@tonic-gate * suggestion from Terrel Larson <terr@terralogic.net> 136*0Sstevel@tonic-gate * who also stands for the is_endian union:-) 137*0Sstevel@tonic-gate * 138*0Sstevel@tonic-gate * Special notes. 139*0Sstevel@tonic-gate * 140*0Sstevel@tonic-gate * - is_endian is declared automatic as doing otherwise 141*0Sstevel@tonic-gate * (declaring static) prevents gcc from eliminating 142*0Sstevel@tonic-gate * the redundant code; 143*0Sstevel@tonic-gate * - compilers (those I've tried) don't seem to have 144*0Sstevel@tonic-gate * problems eliminating either the operators guarded 145*0Sstevel@tonic-gate * by "if (sizeof(RC4_CHUNK)==8)" or the condition 146*0Sstevel@tonic-gate * expressions themselves so I've got 'em to replace 147*0Sstevel@tonic-gate * corresponding #ifdefs from the previous version; 148*0Sstevel@tonic-gate * - I chose to let the redundant switch cases when 149*0Sstevel@tonic-gate * sizeof(RC4_CHUNK)!=8 be (were also #ifdefed 150*0Sstevel@tonic-gate * before); 151*0Sstevel@tonic-gate * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in 152*0Sstevel@tonic-gate * [LB]ESHFT guards against "shift is out of range" 153*0Sstevel@tonic-gate * warnings when sizeof(RC4_CHUNK)!=8 154*0Sstevel@tonic-gate * 155*0Sstevel@tonic-gate * <appro@fy.chalmers.se> 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate if (!is_endian.little) 158*0Sstevel@tonic-gate { /* BIG-ENDIAN CASE */ 159*0Sstevel@tonic-gate # define BESHFT(c) (((sizeof(RC4_CHUNK)-(c)-1)*8)&(sizeof(RC4_CHUNK)*8-1)) 160*0Sstevel@tonic-gate for (;len&-sizeof(RC4_CHUNK);len-=sizeof(RC4_CHUNK)) 161*0Sstevel@tonic-gate { 162*0Sstevel@tonic-gate ichunk = *(RC4_CHUNK *)indata; 163*0Sstevel@tonic-gate otp = RC4_STEP<<BESHFT(0); 164*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(1); 165*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(2); 166*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(3); 167*0Sstevel@tonic-gate if (sizeof(RC4_CHUNK)==8) 168*0Sstevel@tonic-gate { 169*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(4); 170*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(5); 171*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(6); 172*0Sstevel@tonic-gate otp |= RC4_STEP<<BESHFT(7); 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate *(RC4_CHUNK *)outdata = otp^ichunk; 175*0Sstevel@tonic-gate indata += sizeof(RC4_CHUNK); 176*0Sstevel@tonic-gate outdata += sizeof(RC4_CHUNK); 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate if (len) 179*0Sstevel@tonic-gate { 180*0Sstevel@tonic-gate RC4_CHUNK mask=(RC4_CHUNK)-1, ochunk; 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate ichunk = *(RC4_CHUNK *)indata; 183*0Sstevel@tonic-gate ochunk = *(RC4_CHUNK *)outdata; 184*0Sstevel@tonic-gate otp = 0; 185*0Sstevel@tonic-gate i = BESHFT(0); 186*0Sstevel@tonic-gate mask <<= (sizeof(RC4_CHUNK)-len)<<3; 187*0Sstevel@tonic-gate switch (len&(sizeof(RC4_CHUNK)-1)) 188*0Sstevel@tonic-gate { 189*0Sstevel@tonic-gate case 7: otp = RC4_STEP<<i, i-=8; 190*0Sstevel@tonic-gate case 6: otp |= RC4_STEP<<i, i-=8; 191*0Sstevel@tonic-gate case 5: otp |= RC4_STEP<<i, i-=8; 192*0Sstevel@tonic-gate case 4: otp |= RC4_STEP<<i, i-=8; 193*0Sstevel@tonic-gate case 3: otp |= RC4_STEP<<i, i-=8; 194*0Sstevel@tonic-gate case 2: otp |= RC4_STEP<<i, i-=8; 195*0Sstevel@tonic-gate case 1: otp |= RC4_STEP<<i, i-=8; 196*0Sstevel@tonic-gate case 0: ; /* 197*0Sstevel@tonic-gate * it's never the case, 198*0Sstevel@tonic-gate * but it has to be here 199*0Sstevel@tonic-gate * for ultrix? 200*0Sstevel@tonic-gate */ 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate ochunk &= ~mask; 203*0Sstevel@tonic-gate ochunk |= (otp^ichunk) & mask; 204*0Sstevel@tonic-gate *(RC4_CHUNK *)outdata = ochunk; 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate key->x=x; 207*0Sstevel@tonic-gate key->y=y; 208*0Sstevel@tonic-gate return; 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate else 211*0Sstevel@tonic-gate { /* LITTLE-ENDIAN CASE */ 212*0Sstevel@tonic-gate # define LESHFT(c) (((c)*8)&(sizeof(RC4_CHUNK)*8-1)) 213*0Sstevel@tonic-gate for (;len&-sizeof(RC4_CHUNK);len-=sizeof(RC4_CHUNK)) 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate ichunk = *(RC4_CHUNK *)indata; 216*0Sstevel@tonic-gate otp = RC4_STEP; 217*0Sstevel@tonic-gate otp |= RC4_STEP<<8; 218*0Sstevel@tonic-gate otp |= RC4_STEP<<16; 219*0Sstevel@tonic-gate otp |= RC4_STEP<<24; 220*0Sstevel@tonic-gate if (sizeof(RC4_CHUNK)==8) 221*0Sstevel@tonic-gate { 222*0Sstevel@tonic-gate otp |= RC4_STEP<<LESHFT(4); 223*0Sstevel@tonic-gate otp |= RC4_STEP<<LESHFT(5); 224*0Sstevel@tonic-gate otp |= RC4_STEP<<LESHFT(6); 225*0Sstevel@tonic-gate otp |= RC4_STEP<<LESHFT(7); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate *(RC4_CHUNK *)outdata = otp^ichunk; 228*0Sstevel@tonic-gate indata += sizeof(RC4_CHUNK); 229*0Sstevel@tonic-gate outdata += sizeof(RC4_CHUNK); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate if (len) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate RC4_CHUNK mask=(RC4_CHUNK)-1, ochunk; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate ichunk = *(RC4_CHUNK *)indata; 236*0Sstevel@tonic-gate ochunk = *(RC4_CHUNK *)outdata; 237*0Sstevel@tonic-gate otp = 0; 238*0Sstevel@tonic-gate i = 0; 239*0Sstevel@tonic-gate mask >>= (sizeof(RC4_CHUNK)-len)<<3; 240*0Sstevel@tonic-gate switch (len&(sizeof(RC4_CHUNK)-1)) 241*0Sstevel@tonic-gate { 242*0Sstevel@tonic-gate case 7: otp = RC4_STEP, i+=8; 243*0Sstevel@tonic-gate case 6: otp |= RC4_STEP<<i, i+=8; 244*0Sstevel@tonic-gate case 5: otp |= RC4_STEP<<i, i+=8; 245*0Sstevel@tonic-gate case 4: otp |= RC4_STEP<<i, i+=8; 246*0Sstevel@tonic-gate case 3: otp |= RC4_STEP<<i, i+=8; 247*0Sstevel@tonic-gate case 2: otp |= RC4_STEP<<i, i+=8; 248*0Sstevel@tonic-gate case 1: otp |= RC4_STEP<<i, i+=8; 249*0Sstevel@tonic-gate case 0: ; /* 250*0Sstevel@tonic-gate * it's never the case, 251*0Sstevel@tonic-gate * but it has to be here 252*0Sstevel@tonic-gate * for ultrix? 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate ochunk &= ~mask; 256*0Sstevel@tonic-gate ochunk |= (otp^ichunk) & mask; 257*0Sstevel@tonic-gate *(RC4_CHUNK *)outdata = ochunk; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate key->x=x; 260*0Sstevel@tonic-gate key->y=y; 261*0Sstevel@tonic-gate return; 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate #endif 265*0Sstevel@tonic-gate #define LOOP(in,out) \ 266*0Sstevel@tonic-gate x=((x+1)&0xff); \ 267*0Sstevel@tonic-gate tx=d[x]; \ 268*0Sstevel@tonic-gate y=(tx+y)&0xff; \ 269*0Sstevel@tonic-gate d[x]=ty=d[y]; \ 270*0Sstevel@tonic-gate d[y]=tx; \ 271*0Sstevel@tonic-gate (out) = d[(tx+ty)&0xff]^ (in); 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate #ifndef RC4_INDEX 274*0Sstevel@tonic-gate #define RC4_LOOP(a,b,i) LOOP(*((a)++),*((b)++)) 275*0Sstevel@tonic-gate #else 276*0Sstevel@tonic-gate #define RC4_LOOP(a,b,i) LOOP(a[i],b[i]) 277*0Sstevel@tonic-gate #endif 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate i=(int)(len>>3L); 280*0Sstevel@tonic-gate if (i) 281*0Sstevel@tonic-gate { 282*0Sstevel@tonic-gate for (;;) 283*0Sstevel@tonic-gate { 284*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,0); 285*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,1); 286*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,2); 287*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,3); 288*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,4); 289*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,5); 290*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,6); 291*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,7); 292*0Sstevel@tonic-gate #ifdef RC4_INDEX 293*0Sstevel@tonic-gate indata+=8; 294*0Sstevel@tonic-gate outdata+=8; 295*0Sstevel@tonic-gate #endif 296*0Sstevel@tonic-gate if (--i == 0) break; 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate i=(int)len&0x07; 300*0Sstevel@tonic-gate if (i) 301*0Sstevel@tonic-gate { 302*0Sstevel@tonic-gate for (;;) 303*0Sstevel@tonic-gate { 304*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,0); if (--i == 0) break; 305*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,1); if (--i == 0) break; 306*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,2); if (--i == 0) break; 307*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,3); if (--i == 0) break; 308*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,4); if (--i == 0) break; 309*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,5); if (--i == 0) break; 310*0Sstevel@tonic-gate RC4_LOOP(indata,outdata,6); if (--i == 0) break; 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate key->x=x; 314*0Sstevel@tonic-gate key->y=y; 315*0Sstevel@tonic-gate } 316