You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ref.c 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #include "config.h"
  2. #include "chacha.h"
  3. #include "cryptobox.h"
  4. #if defined(HAVE_INT32)
  5. typedef uint32_t chacha_int32;
  6. #else
  7. typedef uint32_t chacha_int32;
  8. #endif
  9. /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
  10. static chacha_int32
  11. U8TO32(const unsigned char *p)
  12. {
  13. return (((chacha_int32) (p[0])) |
  14. ((chacha_int32) (p[1]) << 8) |
  15. ((chacha_int32) (p[2]) << 16) |
  16. ((chacha_int32) (p[3]) << 24));
  17. }
  18. /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
  19. static void
  20. U32TO8(unsigned char *p, chacha_int32 v)
  21. {
  22. p[0] = (v) &0xff;
  23. p[1] = (v >> 8) & 0xff;
  24. p[2] = (v >> 16) & 0xff;
  25. p[3] = (v >> 24) & 0xff;
  26. }
  27. /* 32 bit left rotate */
  28. static chacha_int32
  29. ROTL32(chacha_int32 x, int k)
  30. {
  31. return ((x << k) | (x >> (32 - k))) & 0xffffffff;
  32. }
  33. /* "expand 32-byte k", as 4 little endian 32-bit unsigned integers */
  34. static const chacha_int32 chacha_constants[4] = {
  35. 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
  36. void chacha_blocks_ref(chacha_state_internal *state, const unsigned char *in, unsigned char *out, size_t bytes)
  37. {
  38. chacha_int32 x[16], j[12];
  39. chacha_int32 t;
  40. unsigned char *ctarget = out, tmp[64];
  41. size_t i, r;
  42. if (!bytes) return;
  43. j[0] = U8TO32(state->s + 0);
  44. j[1] = U8TO32(state->s + 4);
  45. j[2] = U8TO32(state->s + 8);
  46. j[3] = U8TO32(state->s + 12);
  47. j[4] = U8TO32(state->s + 16);
  48. j[5] = U8TO32(state->s + 20);
  49. j[6] = U8TO32(state->s + 24);
  50. j[7] = U8TO32(state->s + 28);
  51. j[8] = U8TO32(state->s + 32);
  52. j[9] = U8TO32(state->s + 36);
  53. j[10] = U8TO32(state->s + 40);
  54. j[11] = U8TO32(state->s + 44);
  55. r = state->rounds;
  56. for (;;) {
  57. if (bytes < 64) {
  58. if (in) {
  59. for (i = 0; i < bytes; i++) tmp[i] = in[i];
  60. in = tmp;
  61. }
  62. ctarget = out;
  63. out = tmp;
  64. }
  65. x[0] = chacha_constants[0];
  66. x[1] = chacha_constants[1];
  67. x[2] = chacha_constants[2];
  68. x[3] = chacha_constants[3];
  69. x[4] = j[0];
  70. x[5] = j[1];
  71. x[6] = j[2];
  72. x[7] = j[3];
  73. x[8] = j[4];
  74. x[9] = j[5];
  75. x[10] = j[6];
  76. x[11] = j[7];
  77. x[12] = j[8];
  78. x[13] = j[9];
  79. x[14] = j[10];
  80. x[15] = j[11];
  81. #define quarter(a, b, c, d) \
  82. a += b; \
  83. t = d ^ a; \
  84. d = ROTL32(t, 16); \
  85. c += d; \
  86. t = b ^ c; \
  87. b = ROTL32(t, 12); \
  88. a += b; \
  89. t = d ^ a; \
  90. d = ROTL32(t, 8); \
  91. c += d; \
  92. t = b ^ c; \
  93. b = ROTL32(t, 7);
  94. #define doubleround() \
  95. quarter(x[0], x[4], x[8], x[12]) \
  96. quarter(x[1], x[5], x[9], x[13]) \
  97. quarter(x[2], x[6], x[10], x[14]) \
  98. quarter(x[3], x[7], x[11], x[15]) \
  99. quarter(x[0], x[5], x[10], x[15]) \
  100. quarter(x[1], x[6], x[11], x[12]) \
  101. quarter(x[2], x[7], x[8], x[13]) \
  102. quarter(x[3], x[4], x[9], x[14])
  103. i = r;
  104. do {
  105. doubleround()
  106. i -= 2;
  107. } while (i);
  108. x[0] += chacha_constants[0];
  109. x[1] += chacha_constants[1];
  110. x[2] += chacha_constants[2];
  111. x[3] += chacha_constants[3];
  112. x[4] += j[0];
  113. x[5] += j[1];
  114. x[6] += j[2];
  115. x[7] += j[3];
  116. x[8] += j[4];
  117. x[9] += j[5];
  118. x[10] += j[6];
  119. x[11] += j[7];
  120. x[12] += j[8];
  121. x[13] += j[9];
  122. x[14] += j[10];
  123. x[15] += j[11];
  124. if (in) {
  125. U32TO8(out + 0, x[0] ^ U8TO32(in + 0));
  126. U32TO8(out + 4, x[1] ^ U8TO32(in + 4));
  127. U32TO8(out + 8, x[2] ^ U8TO32(in + 8));
  128. U32TO8(out + 12, x[3] ^ U8TO32(in + 12));
  129. U32TO8(out + 16, x[4] ^ U8TO32(in + 16));
  130. U32TO8(out + 20, x[5] ^ U8TO32(in + 20));
  131. U32TO8(out + 24, x[6] ^ U8TO32(in + 24));
  132. U32TO8(out + 28, x[7] ^ U8TO32(in + 28));
  133. U32TO8(out + 32, x[8] ^ U8TO32(in + 32));
  134. U32TO8(out + 36, x[9] ^ U8TO32(in + 36));
  135. U32TO8(out + 40, x[10] ^ U8TO32(in + 40));
  136. U32TO8(out + 44, x[11] ^ U8TO32(in + 44));
  137. U32TO8(out + 48, x[12] ^ U8TO32(in + 48));
  138. U32TO8(out + 52, x[13] ^ U8TO32(in + 52));
  139. U32TO8(out + 56, x[14] ^ U8TO32(in + 56));
  140. U32TO8(out + 60, x[15] ^ U8TO32(in + 60));
  141. in += 64;
  142. }
  143. else {
  144. U32TO8(out + 0, x[0]);
  145. U32TO8(out + 4, x[1]);
  146. U32TO8(out + 8, x[2]);
  147. U32TO8(out + 12, x[3]);
  148. U32TO8(out + 16, x[4]);
  149. U32TO8(out + 20, x[5]);
  150. U32TO8(out + 24, x[6]);
  151. U32TO8(out + 28, x[7]);
  152. U32TO8(out + 32, x[8]);
  153. U32TO8(out + 36, x[9]);
  154. U32TO8(out + 40, x[10]);
  155. U32TO8(out + 44, x[11]);
  156. U32TO8(out + 48, x[12]);
  157. U32TO8(out + 52, x[13]);
  158. U32TO8(out + 56, x[14]);
  159. U32TO8(out + 60, x[15]);
  160. }
  161. /* increment the 64 bit counter, split in to two 32 bit halves */
  162. j[8]++;
  163. if (!j[8])
  164. j[9]++;
  165. if (bytes <= 64) {
  166. if (bytes < 64)
  167. for (i = 0; i < bytes; i++) ctarget[i] = out[i];
  168. /* store the counter back to the state */
  169. U32TO8(state->s + 32, j[8]);
  170. U32TO8(state->s + 36, j[9]);
  171. goto cleanup;
  172. }
  173. bytes -= 64;
  174. out += 64;
  175. }
  176. cleanup:
  177. rspamd_explicit_memzero(j, sizeof(j));
  178. }
  179. void hchacha_ref(const unsigned char key[32], const unsigned char iv[16], unsigned char out[32], size_t rounds)
  180. {
  181. chacha_int32 x[16];
  182. chacha_int32 t;
  183. x[0] = chacha_constants[0];
  184. x[1] = chacha_constants[1];
  185. x[2] = chacha_constants[2];
  186. x[3] = chacha_constants[3];
  187. x[4] = U8TO32(key + 0);
  188. x[5] = U8TO32(key + 4);
  189. x[6] = U8TO32(key + 8);
  190. x[7] = U8TO32(key + 12);
  191. x[8] = U8TO32(key + 16);
  192. x[9] = U8TO32(key + 20);
  193. x[10] = U8TO32(key + 24);
  194. x[11] = U8TO32(key + 28);
  195. x[12] = U8TO32(iv + 0);
  196. x[13] = U8TO32(iv + 4);
  197. x[14] = U8TO32(iv + 8);
  198. x[15] = U8TO32(iv + 12);
  199. do {
  200. doubleround()
  201. rounds -= 2;
  202. } while (rounds);
  203. /* indices for the chacha constant */
  204. U32TO8(out + 0, x[0]);
  205. U32TO8(out + 4, x[1]);
  206. U32TO8(out + 8, x[2]);
  207. U32TO8(out + 12, x[3]);
  208. /* indices for the iv */
  209. U32TO8(out + 16, x[12]);
  210. U32TO8(out + 20, x[13]);
  211. U32TO8(out + 24, x[14]);
  212. U32TO8(out + 28, x[15]);
  213. }
  214. void chacha_clear_state_ref(chacha_state_internal *state)
  215. {
  216. rspamd_explicit_memzero(state, 48);
  217. }
  218. void chacha_ref(const chacha_key *key, const chacha_iv *iv, const unsigned char *in, unsigned char *out, size_t inlen, size_t rounds)
  219. {
  220. chacha_state_internal state;
  221. size_t i;
  222. for (i = 0; i < 32; i++)
  223. state.s[i + 0] = key->b[i];
  224. for (i = 0; i < 8; i++)
  225. state.s[i + 32] = 0;
  226. for (i = 0; i < 8; i++)
  227. state.s[i + 40] = iv->b[i];
  228. state.rounds = rounds;
  229. chacha_blocks_ref(&state, in, out, inlen);
  230. chacha_clear_state_ref(&state);
  231. }
  232. void xchacha_ref(const chacha_key *key, const chacha_iv24 *iv, const unsigned char *in, unsigned char *out, size_t inlen, size_t rounds)
  233. {
  234. chacha_state_internal state;
  235. size_t i;
  236. hchacha_ref(key->b, iv->b, &state.s[0], rounds);
  237. for (i = 0; i < 8; i++)
  238. state.s[i + 32] = 0;
  239. for (i = 0; i < 8; i++)
  240. state.s[i + 40] = iv->b[i + 16];
  241. state.rounds = rounds;
  242. chacha_blocks_ref(&state, in, out, inlen);
  243. chacha_clear_state_ref(&state);
  244. }