chacha20.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /* ===================================================================
  2. *
  3. * Copyright (c) 2014, Legrandin <helderijs@gmail.com>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in
  14. * the documentation and/or other materials provided with the
  15. * distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. * ===================================================================
  30. */
  31. #include "common.h"
  32. #include "endianess.h"
  33. FAKE_INIT(chacha20)
  34. #define KEY_SIZE 32
  35. typedef struct {
  36. /** Initial state for the next iteration **/
  37. uint32_t h[16];
  38. size_t nonceSize; /** in bytes **/
  39. /** How many bytes at the beginning of the key stream
  40. * have already been used.
  41. */
  42. unsigned usedKeyStream;
  43. uint8_t keyStream[sizeof(uint32_t)*16];
  44. } stream_state;
  45. #define ROTL(q, n) (((q) << (n)) | ((q) >> (32 - (n))))
  46. #define QR(a, b, c, d) {\
  47. a+=b; d^=a; d=ROTL(d,16); \
  48. c+=d; b^=c; b=ROTL(b,12); \
  49. a+=b; d^=a; d=ROTL(d,8); \
  50. c+=d; b^=c; b=ROTL(b,7); \
  51. }
  52. EXPORT_SYM int chacha20_init(stream_state **pState,
  53. const uint8_t *key,
  54. size_t keySize,
  55. const uint8_t *nonce,
  56. size_t nonceSize)
  57. {
  58. stream_state *hs;
  59. unsigned i;
  60. if (NULL == pState || NULL == nonce)
  61. return ERR_NULL;
  62. if (NULL == key || keySize != KEY_SIZE)
  63. return ERR_KEY_SIZE;
  64. if (nonceSize != 8 && nonceSize != 12 && nonceSize != 16)
  65. return ERR_NONCE_SIZE;
  66. *pState = hs = (stream_state*) calloc(1, sizeof(stream_state));
  67. if (NULL == hs)
  68. return ERR_MEMORY;
  69. hs->h[0] = 0x61707865;
  70. hs->h[1] = 0x3320646e;
  71. hs->h[2] = 0x79622d32;
  72. hs->h[3] = 0x6b206574;
  73. /** Move 256-bit/32-byte key into h[4..11] **/
  74. for (i=0; i<32/4; i++) {
  75. hs->h[4+i] = LOAD_U32_LITTLE(key + 4*i);
  76. }
  77. switch (nonceSize) {
  78. case 8: {
  79. /*
  80. cccccccc cccccccc cccccccc cccccccc
  81. kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
  82. kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
  83. bbbbbbbb BBBBBBBB nnnnnnnn nnnnnnnn
  84. c=constant k=key b=blockcount(low) B=blockcount(high) n=nonce
  85. */
  86. /** h[12] remains 0 (offset) **/
  87. /** h[13] remains 0 (offset) **/
  88. hs->h[14] = LOAD_U32_LITTLE(nonce + 0);
  89. hs->h[15] = LOAD_U32_LITTLE(nonce + 4);
  90. break;
  91. }
  92. case 12: {
  93. /*
  94. cccccccc cccccccc cccccccc cccccccc
  95. kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
  96. kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
  97. bbbbbbbb nnnnnnnn nnnnnnnn nnnnnnnn
  98. c=constant k=key b=blockcount n=nonce
  99. */
  100. /** h[12] remains 0 (offset) **/
  101. hs->h[13] = LOAD_U32_LITTLE(nonce + 0);
  102. hs->h[14] = LOAD_U32_LITTLE(nonce + 4);
  103. hs->h[15] = LOAD_U32_LITTLE(nonce + 8);
  104. break;
  105. }
  106. case 16: {
  107. /*
  108. cccccccc cccccccc cccccccc cccccccc
  109. kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
  110. kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
  111. nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn
  112. c=constant k=key n=nonce
  113. */
  114. hs->h[12] = LOAD_U32_LITTLE(nonce + 0);
  115. hs->h[13] = LOAD_U32_LITTLE(nonce + 4);
  116. hs->h[14] = LOAD_U32_LITTLE(nonce + 8);
  117. hs->h[15] = LOAD_U32_LITTLE(nonce + 12);
  118. break;
  119. }
  120. default:
  121. return ERR_NONCE_SIZE;
  122. }
  123. hs->nonceSize = nonceSize;
  124. hs->usedKeyStream = sizeof hs->keyStream;
  125. return 0;
  126. }
  127. EXPORT_SYM int chacha20_destroy(stream_state *state)
  128. {
  129. if (NULL == state)
  130. return ERR_NULL;
  131. free(state);
  132. return 0;
  133. }
  134. static int chacha20_core(stream_state *state, uint32_t h[16])
  135. {
  136. unsigned i;
  137. memcpy(h, state->h, sizeof state->h);
  138. for (i=0; i<10; i++) {
  139. /** Column round **/
  140. QR(h[0], h[4], h[ 8], h[12]);
  141. QR(h[1], h[5], h[ 9], h[13]);
  142. QR(h[2], h[6], h[10], h[14]);
  143. QR(h[3], h[7], h[11], h[15]);
  144. /** Diagonal round **/
  145. QR(h[0], h[5], h[10], h[15]);
  146. QR(h[1], h[6], h[11], h[12]);
  147. QR(h[2], h[7], h[ 8], h[13]);
  148. QR(h[3], h[4], h[ 9], h[14]);
  149. }
  150. for (i=0; i<16; i++) {
  151. uint32_t sum;
  152. sum = h[i] + state->h[i];
  153. STORE_U32_LITTLE(state->keyStream + 4*i, sum);
  154. }
  155. state->usedKeyStream = 0;
  156. switch (state->nonceSize) {
  157. case 8: {
  158. /** Nonce is 64 bits, counter is two words **/
  159. if (++state->h[12] == 0) {
  160. if (++state->h[13] == 0) {
  161. return ERR_MAX_DATA;
  162. }
  163. }
  164. break;
  165. }
  166. case 12: {
  167. /** Nonce is 96 bits, counter is one word **/
  168. if (++state->h[12] == 0) {
  169. return ERR_MAX_DATA;
  170. }
  171. break;
  172. }
  173. case 16: {
  174. /** Nonce is 192 bits, there is no counter as this is intended
  175. * to be run once only (HChaCha20) **/
  176. break;
  177. }
  178. }
  179. return 0;
  180. }
  181. EXPORT_SYM int chacha20_encrypt(stream_state *state,
  182. const uint8_t in[],
  183. uint8_t out[],
  184. size_t len)
  185. {
  186. if (NULL == state || NULL == in || NULL == out)
  187. return ERR_NULL;
  188. if ((state->nonceSize != 8) && (state->nonceSize != 12))
  189. return ERR_NONCE_SIZE;
  190. while (len>0) {
  191. unsigned keyStreamToUse;
  192. unsigned i;
  193. uint32_t h[16];
  194. if (state->usedKeyStream == sizeof state->keyStream) {
  195. int result;
  196. result = chacha20_core(state, h);
  197. if (result)
  198. return result;
  199. }
  200. keyStreamToUse = (unsigned)MIN(len, sizeof state->keyStream - state->usedKeyStream);
  201. for (i=0; i<keyStreamToUse; i++)
  202. *out++ = *in++ ^ state->keyStream[i + state->usedKeyStream];
  203. len -= keyStreamToUse;
  204. state->usedKeyStream += keyStreamToUse;
  205. }
  206. return 0;
  207. }
  208. EXPORT_SYM int chacha20_seek(stream_state *state,
  209. unsigned long block_high,
  210. unsigned long block_low,
  211. unsigned offset)
  212. {
  213. int result;
  214. uint32_t h[16];
  215. if (NULL == state)
  216. return ERR_NULL;
  217. if ((state->nonceSize != 8) && (state->nonceSize != 12))
  218. return ERR_NONCE_SIZE;
  219. if (offset >= sizeof state->keyStream)
  220. return ERR_MAX_OFFSET;
  221. if (state->nonceSize == 8) {
  222. /** Nonce is 64 bits, counter is two words **/
  223. state->h[12] = (uint32_t)block_low;
  224. state->h[13] = (uint32_t)block_high;
  225. } else {
  226. /** Nonce is 96 bits, counter is one word **/
  227. if (block_high > 0) {
  228. return ERR_MAX_OFFSET;
  229. }
  230. state->h[12] = (uint32_t)block_low;
  231. }
  232. result = chacha20_core(state, h);
  233. if (result)
  234. return result;
  235. state->usedKeyStream = offset;
  236. return 0;
  237. }
  238. /*
  239. * Based on https://tools.ietf.org/html/draft-arciszewski-xchacha-03
  240. */
  241. EXPORT_SYM int hchacha20(const uint8_t key[KEY_SIZE],
  242. const uint8_t nonce16[16], /* First 16 bytes of the 24 byte nonce */
  243. uint8_t subkey[KEY_SIZE])
  244. {
  245. stream_state *pState;
  246. uint32_t h[16];
  247. if (NULL == key || NULL == nonce16 || NULL == subkey) {
  248. return ERR_NULL;
  249. }
  250. chacha20_init(&pState, key, KEY_SIZE, nonce16, 16);
  251. if (NULL == pState)
  252. return ERR_MEMORY;
  253. chacha20_core(pState, h);
  254. /* We only keep first and last row from the new state */
  255. STORE_U32_LITTLE(subkey + 0, h[0]);
  256. STORE_U32_LITTLE(subkey + 4, h[1]);
  257. STORE_U32_LITTLE(subkey + 8, h[2]);
  258. STORE_U32_LITTLE(subkey + 12, h[3]);
  259. STORE_U32_LITTLE(subkey + 16, h[12]);
  260. STORE_U32_LITTLE(subkey + 20, h[13]);
  261. STORE_U32_LITTLE(subkey + 24, h[14]);
  262. STORE_U32_LITTLE(subkey + 28, h[15]);
  263. chacha20_destroy(pState);
  264. return 0;
  265. }
  266. #ifdef PROFILE
  267. int main(void)
  268. {
  269. const unsigned data_size = 1024*1024;
  270. const uint8_t key[32] = "12345678901234561234567890123456";
  271. const uint8_t nonce[8] = "12345678";
  272. stream_state *state;
  273. uint8_t *data;
  274. data = malloc(data_size);
  275. for (int i=0; i<data_size; i++) {
  276. data[i] = (uint8_t) i;
  277. }
  278. chacha20_init(&state, key, 32, nonce, 8);
  279. for (int i=0; i<1024; i++)
  280. chacha20_encrypt(state, data, data, data_size);
  281. chacha20_destroy(state);
  282. free(data);
  283. }
  284. #endif