2
0

rc4.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* LibTomCrypt, modular cryptographic library -- Tom St Denis
  2. *
  3. * LibTomCrypt is a library that provides various cryptographic
  4. * algorithms in a highly modular and flexible manner.
  5. *
  6. * The library is free for all purposes without any express
  7. * guarantee it works.
  8. *
  9. * Tom St Denis, [email protected], http://libtomcrypt.org
  10. */
  11. #include "mycrypt.h"
  12. #ifdef RC4
  13. const struct _prng_descriptor rc4_desc =
  14. {
  15. "rc4", 32,
  16. &rc4_start,
  17. &rc4_add_entropy,
  18. &rc4_ready,
  19. &rc4_read,
  20. &rc4_done,
  21. &rc4_export,
  22. &rc4_import,
  23. &rc4_test
  24. };
  25. int rc4_start(prng_state *prng)
  26. {
  27. _ARGCHK(prng != NULL);
  28. /* set keysize to zero */
  29. prng->rc4.x = 0;
  30. return CRYPT_OK;
  31. }
  32. int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng)
  33. {
  34. _ARGCHK(buf != NULL);
  35. _ARGCHK(prng != NULL);
  36. /* trim as required */
  37. if (prng->rc4.x + len > 256) {
  38. if (prng->rc4.x == 256) {
  39. /* I can't possibly accept another byte, ok maybe a mint wafer... */
  40. return CRYPT_OK;
  41. } else {
  42. /* only accept part of it */
  43. len = 256 - prng->rc4.x;
  44. }
  45. }
  46. while (len--) {
  47. prng->rc4.buf[prng->rc4.x++] = *buf++;
  48. }
  49. return CRYPT_OK;
  50. }
  51. int rc4_ready(prng_state *prng)
  52. {
  53. unsigned char key[256], tmp, *s;
  54. int keylen, x, y, j;
  55. _ARGCHK(prng != NULL);
  56. /* extract the key */
  57. s = prng->rc4.buf;
  58. XMEMCPY(key, s, 256);
  59. keylen = prng->rc4.x;
  60. /* make RC4 perm and shuffle */
  61. for (x = 0; x < 256; x++) {
  62. s[x] = x;
  63. }
  64. for (j = x = y = 0; x < 256; x++) {
  65. y = (y + prng->rc4.buf[x] + key[j++]) & 255;
  66. if (j == keylen) {
  67. j = 0;
  68. }
  69. tmp = s[x]; s[x] = s[y]; s[y] = tmp;
  70. }
  71. prng->rc4.x = 0;
  72. prng->rc4.y = 0;
  73. #ifdef CLEAN_STACK
  74. zeromem(key, sizeof(key));
  75. #endif
  76. return CRYPT_OK;
  77. }
  78. unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng)
  79. {
  80. unsigned char x, y, *s, tmp;
  81. unsigned long n;
  82. _ARGCHK(buf != NULL);
  83. _ARGCHK(prng != NULL);
  84. n = len;
  85. x = prng->rc4.x;
  86. y = prng->rc4.y;
  87. s = prng->rc4.buf;
  88. while (len--) {
  89. x = (x + 1) & 255;
  90. y = (y + s[x]) & 255;
  91. tmp = s[x]; s[x] = s[y]; s[y] = tmp;
  92. tmp = (s[x] + s[y]) & 255;
  93. *buf++ ^= s[tmp];
  94. }
  95. prng->rc4.x = x;
  96. prng->rc4.y = y;
  97. return n;
  98. }
  99. int rc4_done(prng_state *prng)
  100. {
  101. _ARGCHK(prng != NULL);
  102. return CRYPT_OK;
  103. }
  104. int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
  105. {
  106. _ARGCHK(outlen != NULL);
  107. _ARGCHK(out != NULL);
  108. _ARGCHK(prng != NULL);
  109. if (*outlen < 32) {
  110. return CRYPT_BUFFER_OVERFLOW;
  111. }
  112. if (rc4_read(out, 32, prng) != 32) {
  113. return CRYPT_ERROR_READPRNG;
  114. }
  115. *outlen = 32;
  116. return CRYPT_OK;
  117. }
  118. int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
  119. {
  120. int err;
  121. _ARGCHK(in != NULL);
  122. _ARGCHK(prng != NULL);
  123. if (inlen != 32) {
  124. return CRYPT_INVALID_ARG;
  125. }
  126. if ((err = rc4_start(prng)) != CRYPT_OK) {
  127. return err;
  128. }
  129. return rc4_add_entropy(in, 32, prng);
  130. }
  131. int rc4_test(void)
  132. {
  133. #ifndef LTC_TEST
  134. return CRYPT_NOP;
  135. #else
  136. static const struct {
  137. unsigned char key[8], pt[8], ct[8];
  138. } tests[] = {
  139. {
  140. { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
  141. { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
  142. { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }
  143. }
  144. };
  145. prng_state prng;
  146. unsigned char dst[8];
  147. int err, x;
  148. for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
  149. if ((err = rc4_start(&prng)) != CRYPT_OK) {
  150. return err;
  151. }
  152. if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) {
  153. return err;
  154. }
  155. if ((err = rc4_ready(&prng)) != CRYPT_OK) {
  156. return err;
  157. }
  158. XMEMCPY(dst, tests[x].pt, 8);
  159. if (rc4_read(dst, 8, &prng) != 8) {
  160. return CRYPT_ERROR_READPRNG;
  161. }
  162. rc4_done(&prng);
  163. if (memcmp(dst, tests[x].ct, 8)) {
  164. #if 0
  165. int y;
  166. printf("\n\nRC4 failed, I got:\n");
  167. for (y = 0; y < 8; y++) printf("%02x ", dst[y]);
  168. printf("\n");
  169. #endif
  170. return CRYPT_FAIL_TESTVECTOR;
  171. }
  172. }
  173. return CRYPT_OK;
  174. #endif
  175. }
  176. #endif