rc4_enc.c 10 KB

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