rc4_enc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. /*-
  61. * RC4 as implemented from a posting from
  62. * Newsgroups: sci.crypt
  63. * From: sterndark@netcom.com (David Sterndark)
  64. * Subject: RC4 Algorithm revealed.
  65. * Message-ID: <sternCvKL4B.Hyy@netcom.com>
  66. * Date: Wed, 14 Sep 1994 06:35:31 GMT
  67. */
  68. void RC4(RC4_KEY *key, size_t len, const unsigned char *indata,
  69. unsigned char *outdata)
  70. {
  71. register RC4_INT *d;
  72. register RC4_INT x, y, tx, ty;
  73. size_t i;
  74. x = key->x;
  75. y = key->y;
  76. d = key->data;
  77. #if defined(RC4_CHUNK) && !defined(PEDANTIC)
  78. /*-
  79. * The original reason for implementing this(*) was the fact that
  80. * pre-21164a Alpha CPUs don't have byte load/store instructions
  81. * and e.g. a byte store has to be done with 64-bit load, shift,
  82. * and, or and finally 64-bit store. Peaking data and operating
  83. * at natural word size made it possible to reduce amount of
  84. * instructions as well as to perform early read-ahead without
  85. * suffering from RAW (read-after-write) hazard. This resulted
  86. * in ~40%(**) performance improvement on 21064 box with gcc.
  87. * But it's not only Alpha users who win here:-) Thanks to the
  88. * early-n-wide read-ahead this implementation also exhibits
  89. * >40% speed-up on SPARC and 20-30% on 64-bit MIPS (depending
  90. * on sizeof(RC4_INT)).
  91. *
  92. * (*) "this" means code which recognizes the case when input
  93. * and output pointers appear to be aligned at natural CPU
  94. * word boundary
  95. * (**) i.e. according to 'apps/openssl speed rc4' benchmark,
  96. * crypto/rc4/rc4speed.c exhibits almost 70% speed-up...
  97. *
  98. * Cavets.
  99. *
  100. * - RC4_CHUNK="unsigned long long" should be a #1 choice for
  101. * UltraSPARC. Unfortunately gcc generates very slow code
  102. * (2.5-3 times slower than one generated by Sun's WorkShop
  103. * C) and therefore gcc (at least 2.95 and earlier) should
  104. * always be told that RC4_CHUNK="unsigned long".
  105. *
  106. * <appro@fy.chalmers.se>
  107. */
  108. # define RC4_STEP ( \
  109. x=(x+1) &0xff, \
  110. tx=d[x], \
  111. y=(tx+y)&0xff, \
  112. ty=d[y], \
  113. d[y]=tx, \
  114. d[x]=ty, \
  115. (RC4_CHUNK)d[(tx+ty)&0xff]\
  116. )
  117. if ((((size_t)indata & (sizeof(RC4_CHUNK) - 1)) |
  118. ((size_t)outdata & (sizeof(RC4_CHUNK) - 1))) == 0) {
  119. RC4_CHUNK ichunk, otp;
  120. const union {
  121. long one;
  122. char little;
  123. } is_endian = {
  124. 1
  125. };
  126. /*-
  127. * I reckon we can afford to implement both endian
  128. * cases and to decide which way to take at run-time
  129. * because the machine code appears to be very compact
  130. * and redundant 1-2KB is perfectly tolerable (i.e.
  131. * in case the compiler fails to eliminate it:-). By
  132. * suggestion from Terrel Larson <terr@terralogic.net>
  133. * who also stands for the is_endian union:-)
  134. *
  135. * Special notes.
  136. *
  137. * - is_endian is declared automatic as doing otherwise
  138. * (declaring static) prevents gcc from eliminating
  139. * the redundant code;
  140. * - compilers (those I've tried) don't seem to have
  141. * problems eliminating either the operators guarded
  142. * by "if (sizeof(RC4_CHUNK)==8)" or the condition
  143. * expressions themselves so I've got 'em to replace
  144. * corresponding #ifdefs from the previous version;
  145. * - I chose to let the redundant switch cases when
  146. * sizeof(RC4_CHUNK)!=8 be (were also #ifdefed
  147. * before);
  148. * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in
  149. * [LB]ESHFT guards against "shift is out of range"
  150. * warnings when sizeof(RC4_CHUNK)!=8
  151. *
  152. * <appro@fy.chalmers.se>
  153. */
  154. if (!is_endian.little) { /* BIG-ENDIAN CASE */
  155. # define BESHFT(c) (((sizeof(RC4_CHUNK)-(c)-1)*8)&(sizeof(RC4_CHUNK)*8-1))
  156. for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) {
  157. ichunk = *(RC4_CHUNK *) indata;
  158. otp = RC4_STEP << BESHFT(0);
  159. otp |= RC4_STEP << BESHFT(1);
  160. otp |= RC4_STEP << BESHFT(2);
  161. otp |= RC4_STEP << BESHFT(3);
  162. if (sizeof(RC4_CHUNK) == 8) {
  163. otp |= RC4_STEP << BESHFT(4);
  164. otp |= RC4_STEP << BESHFT(5);
  165. otp |= RC4_STEP << BESHFT(6);
  166. otp |= RC4_STEP << BESHFT(7);
  167. }
  168. *(RC4_CHUNK *) outdata = otp ^ ichunk;
  169. indata += sizeof(RC4_CHUNK);
  170. outdata += sizeof(RC4_CHUNK);
  171. }
  172. if (len) {
  173. RC4_CHUNK mask = (RC4_CHUNK) - 1, ochunk;
  174. ichunk = *(RC4_CHUNK *) indata;
  175. ochunk = *(RC4_CHUNK *) outdata;
  176. otp = 0;
  177. i = BESHFT(0);
  178. mask <<= (sizeof(RC4_CHUNK) - len) << 3;
  179. switch (len & (sizeof(RC4_CHUNK) - 1)) {
  180. case 7:
  181. otp = RC4_STEP << i, i -= 8;
  182. case 6:
  183. otp |= RC4_STEP << i, i -= 8;
  184. case 5:
  185. otp |= RC4_STEP << i, i -= 8;
  186. case 4:
  187. otp |= RC4_STEP << i, i -= 8;
  188. case 3:
  189. otp |= RC4_STEP << i, i -= 8;
  190. case 2:
  191. otp |= RC4_STEP << i, i -= 8;
  192. case 1:
  193. otp |= RC4_STEP << i, i -= 8;
  194. case 0:; /*
  195. * it's never the case,
  196. * but it has to be here
  197. * for ultrix?
  198. */
  199. }
  200. ochunk &= ~mask;
  201. ochunk |= (otp ^ ichunk) & mask;
  202. *(RC4_CHUNK *) outdata = ochunk;
  203. }
  204. key->x = x;
  205. key->y = y;
  206. return;
  207. } else { /* LITTLE-ENDIAN CASE */
  208. # define LESHFT(c) (((c)*8)&(sizeof(RC4_CHUNK)*8-1))
  209. for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) {
  210. ichunk = *(RC4_CHUNK *) indata;
  211. otp = RC4_STEP;
  212. otp |= RC4_STEP << 8;
  213. otp |= RC4_STEP << 16;
  214. otp |= RC4_STEP << 24;
  215. if (sizeof(RC4_CHUNK) == 8) {
  216. otp |= RC4_STEP << LESHFT(4);
  217. otp |= RC4_STEP << LESHFT(5);
  218. otp |= RC4_STEP << LESHFT(6);
  219. otp |= RC4_STEP << LESHFT(7);
  220. }
  221. *(RC4_CHUNK *) outdata = otp ^ ichunk;
  222. indata += sizeof(RC4_CHUNK);
  223. outdata += sizeof(RC4_CHUNK);
  224. }
  225. if (len) {
  226. RC4_CHUNK mask = (RC4_CHUNK) - 1, ochunk;
  227. ichunk = *(RC4_CHUNK *) indata;
  228. ochunk = *(RC4_CHUNK *) outdata;
  229. otp = 0;
  230. i = 0;
  231. mask >>= (sizeof(RC4_CHUNK) - len) << 3;
  232. switch (len & (sizeof(RC4_CHUNK) - 1)) {
  233. case 7:
  234. otp = RC4_STEP, i += 8;
  235. case 6:
  236. otp |= RC4_STEP << i, i += 8;
  237. case 5:
  238. otp |= RC4_STEP << i, i += 8;
  239. case 4:
  240. otp |= RC4_STEP << i, i += 8;
  241. case 3:
  242. otp |= RC4_STEP << i, i += 8;
  243. case 2:
  244. otp |= RC4_STEP << i, i += 8;
  245. case 1:
  246. otp |= RC4_STEP << i, i += 8;
  247. case 0:; /*
  248. * it's never the case,
  249. * but it has to be here
  250. * for ultrix?
  251. */
  252. }
  253. ochunk &= ~mask;
  254. ochunk |= (otp ^ ichunk) & mask;
  255. *(RC4_CHUNK *) outdata = ochunk;
  256. }
  257. key->x = x;
  258. key->y = y;
  259. return;
  260. }
  261. }
  262. #endif
  263. #define LOOP(in,out) \
  264. x=((x+1)&0xff); \
  265. tx=d[x]; \
  266. y=(tx+y)&0xff; \
  267. d[x]=ty=d[y]; \
  268. d[y]=tx; \
  269. (out) = d[(tx+ty)&0xff]^ (in);
  270. #ifndef RC4_INDEX
  271. # define RC4_LOOP(a,b,i) LOOP(*((a)++),*((b)++))
  272. #else
  273. # define RC4_LOOP(a,b,i) LOOP(a[i],b[i])
  274. #endif
  275. i = len >> 3;
  276. if (i) {
  277. for (;;) {
  278. RC4_LOOP(indata, outdata, 0);
  279. RC4_LOOP(indata, outdata, 1);
  280. RC4_LOOP(indata, outdata, 2);
  281. RC4_LOOP(indata, outdata, 3);
  282. RC4_LOOP(indata, outdata, 4);
  283. RC4_LOOP(indata, outdata, 5);
  284. RC4_LOOP(indata, outdata, 6);
  285. RC4_LOOP(indata, outdata, 7);
  286. #ifdef RC4_INDEX
  287. indata += 8;
  288. outdata += 8;
  289. #endif
  290. if (--i == 0)
  291. break;
  292. }
  293. }
  294. i = len & 0x07;
  295. if (i) {
  296. for (;;) {
  297. RC4_LOOP(indata, outdata, 0);
  298. if (--i == 0)
  299. break;
  300. RC4_LOOP(indata, outdata, 1);
  301. if (--i == 0)
  302. break;
  303. RC4_LOOP(indata, outdata, 2);
  304. if (--i == 0)
  305. break;
  306. RC4_LOOP(indata, outdata, 3);
  307. if (--i == 0)
  308. break;
  309. RC4_LOOP(indata, outdata, 4);
  310. if (--i == 0)
  311. break;
  312. RC4_LOOP(indata, outdata, 5);
  313. if (--i == 0)
  314. break;
  315. RC4_LOOP(indata, outdata, 6);
  316. if (--i == 0)
  317. break;
  318. }
  319. }
  320. key->x = x;
  321. key->y = y;
  322. }