chacha20.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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 "pycrypto_common.h"
  32. FAKE_INIT(chacha20)
  33. #define KEY_SIZE 32
  34. #define NONCE_SIZE 8
  35. typedef struct {
  36. /** Initial state for the next iteration **/
  37. uint32_t h[16];
  38. /** How many bytes at the beginning of the key stream
  39. * have already been used.
  40. */
  41. uint8_t usedKeyStream;
  42. uint8_t keyStream[sizeof(uint32_t)*16];
  43. } stream_state;
  44. static int littleEndian(void) {
  45. int test = 1;
  46. return *((uint8_t*)&test) == 1;
  47. }
  48. static void byteSwap(uint32_t *v)
  49. {
  50. union {
  51. uint32_t w;
  52. uint8_t b[4];
  53. } x, y;
  54. x.w = *v;
  55. y.b[0] = x.b[3];
  56. y.b[1] = x.b[2];
  57. y.b[2] = x.b[1];
  58. y.b[3] = x.b[0];
  59. *v = y.w;
  60. }
  61. /** Convert status word from little endian to native and vice versa **/
  62. static void fix_endianess(uint32_t h[16], unsigned start, unsigned end)
  63. {
  64. unsigned i;
  65. if (littleEndian())
  66. return;
  67. for (i=start; i<end; i++)
  68. byteSwap(&h[i]);
  69. }
  70. static unsigned minAB(unsigned a, unsigned b) {
  71. return a < b ? a : b;
  72. }
  73. #define ROTL(q, n) (((q) << (n)) | ((q) >> (32 - (n))))
  74. #define QR(a, b, c, d) {\
  75. a+=b; d^=a; d=ROTL(d,16); \
  76. c+=d; b^=c; b=ROTL(b,12); \
  77. a+=b; d^=a; d=ROTL(d,8); \
  78. c+=d; b^=c; b=ROTL(b,7); \
  79. }
  80. EXPORT_SYM int chacha20_init(stream_state **pState,
  81. const uint8_t *key,
  82. size_t keySize,
  83. const uint8_t *nonce,
  84. size_t nonceSize)
  85. {
  86. stream_state *hs;
  87. if (NULL == pState || NULL == nonce)
  88. return ERR_NULL;
  89. if (NULL == key || keySize != KEY_SIZE)
  90. return ERR_KEY_SIZE;
  91. if (NULL == nonce || nonceSize != NONCE_SIZE)
  92. return ERR_NONCE_SIZE;
  93. *pState = hs = (stream_state*) calloc(1, sizeof(stream_state));
  94. if (NULL == hs)
  95. return ERR_MEMORY;
  96. hs->h[0] = 0x61707865;
  97. hs->h[1] = 0x3320646e;
  98. hs->h[2] = 0x79622d32;
  99. hs->h[3] = 0x6b206574;
  100. memcpy(&hs->h[4], key, KEY_SIZE);
  101. fix_endianess(hs->h, 4, 12);
  102. memcpy(&hs->h[14], nonce, NONCE_SIZE);
  103. fix_endianess(hs->h, 14, 16);
  104. hs->usedKeyStream = sizeof hs->keyStream;
  105. return 0;
  106. }
  107. EXPORT_SYM int chacha20_destroy(stream_state *state)
  108. {
  109. if (NULL == state)
  110. return ERR_NULL;
  111. free(state);
  112. return 0;
  113. }
  114. static int chacha20_core(stream_state *state)
  115. {
  116. unsigned i;
  117. uint32_t h[16];
  118. memcpy(h, state->h, sizeof h);
  119. for (i=0; i<10; i++) {
  120. /** Column round **/
  121. QR(h[0], h[4], h[ 8], h[12]);
  122. QR(h[1], h[5], h[ 9], h[13]);
  123. QR(h[2], h[6], h[10], h[14]);
  124. QR(h[3], h[7], h[11], h[15]);
  125. /** Diagonal round **/
  126. QR(h[0], h[5], h[10], h[15]);
  127. QR(h[1], h[6], h[11], h[12]);
  128. QR(h[2], h[7], h[ 8], h[13]);
  129. QR(h[3], h[4], h[ 9], h[14]);
  130. }
  131. for (i=0; i<16; i++)
  132. h[i] += state->h[i];
  133. fix_endianess(h, 0, 16);
  134. memcpy(state->keyStream, h, sizeof h);
  135. state->usedKeyStream = 0;
  136. if (++state->h[12] == 0) {
  137. if (++state->h[13] == 0) {
  138. return ERR_MAX_DATA;
  139. }
  140. }
  141. return 0;
  142. }
  143. EXPORT_SYM int chacha20_encrypt(stream_state *state,
  144. const uint8_t in[],
  145. uint8_t out[],
  146. size_t len)
  147. {
  148. if (NULL == state || NULL == in || NULL == out)
  149. return ERR_NULL;
  150. while (len>0) {
  151. unsigned keyStreamToUse;
  152. unsigned i;
  153. if (state->usedKeyStream == sizeof state->keyStream) {
  154. int result;
  155. result = chacha20_core(state);
  156. if (result)
  157. return result;
  158. }
  159. keyStreamToUse = minAB(len, sizeof state->keyStream - state->usedKeyStream);
  160. for (i=0; i<keyStreamToUse; i++)
  161. *out++ = *in++ ^ state->keyStream[i + state->usedKeyStream];
  162. len -= keyStreamToUse;
  163. state->usedKeyStream += keyStreamToUse;
  164. }
  165. return 0;
  166. }
  167. EXPORT_SYM int chacha20_seek(stream_state *state,
  168. unsigned long block_high,
  169. unsigned long block_low,
  170. unsigned offset)
  171. {
  172. int result;
  173. if (NULL == state)
  174. return ERR_NULL;
  175. if (offset >= sizeof state->keyStream)
  176. return ERR_MAX_OFFSET;
  177. state->h[12] = block_low;
  178. state->h[13] = block_high;
  179. result = chacha20_core(state);
  180. if (result)
  181. return result;
  182. state->usedKeyStream = offset;
  183. return 0;
  184. }