Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

349 строки
12 KiB

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