chacha_enc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /* ====================================================================
  2. * Copyright (c) 2011-2013 The OpenSSL Project. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in
  13. * the documentation and/or other materials provided with the
  14. * distribution.
  15. *
  16. * 3. All advertising materials mentioning features or use of this
  17. * software must display the following acknowledgment:
  18. * "This product includes software developed by the OpenSSL Project
  19. * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
  20. *
  21. * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  22. * endorse or promote products derived from this software without
  23. * prior written permission. For written permission, please contact
  24. * licensing@OpenSSL.org.
  25. *
  26. * 5. Products derived from this software may not be called "OpenSSL"
  27. * nor may "OpenSSL" appear in their names without prior written
  28. * permission of the OpenSSL Project.
  29. *
  30. * 6. Redistributions of any form whatsoever must retain the following
  31. * acknowledgment:
  32. * "This product includes software developed by the OpenSSL Project
  33. * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  36. * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46. * OF THE POSSIBILITY OF SUCH DAMAGE.
  47. * ====================================================================
  48. */
  49. /* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
  50. #include <string.h>
  51. #include "internal/chacha.h"
  52. typedef unsigned int u32;
  53. typedef unsigned char u8;
  54. typedef union {
  55. u32 u[16];
  56. u8 c[64];
  57. } chacha_buf;
  58. # define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
  59. # define U32TO8_LITTLE(p, v) do { \
  60. (p)[0] = (u8)(v >> 0); \
  61. (p)[1] = (u8)(v >> 8); \
  62. (p)[2] = (u8)(v >> 16); \
  63. (p)[3] = (u8)(v >> 24); \
  64. } while(0)
  65. /* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
  66. # define QUARTERROUND(a,b,c,d) ( \
  67. x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]),16), \
  68. x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]),12), \
  69. x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 8), \
  70. x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 7) )
  71. /* chacha_core performs 20 rounds of ChaCha on the input words in
  72. * |input| and writes the 64 output bytes to |output|. */
  73. static void chacha20_core(chacha_buf *output, const u32 input[16])
  74. {
  75. u32 x[16];
  76. int i;
  77. const union {
  78. long one;
  79. char little;
  80. } is_endian = { 1 };
  81. memcpy(x, input, sizeof(x));
  82. for (i = 20; i > 0; i -= 2) {
  83. QUARTERROUND(0, 4, 8, 12);
  84. QUARTERROUND(1, 5, 9, 13);
  85. QUARTERROUND(2, 6, 10, 14);
  86. QUARTERROUND(3, 7, 11, 15);
  87. QUARTERROUND(0, 5, 10, 15);
  88. QUARTERROUND(1, 6, 11, 12);
  89. QUARTERROUND(2, 7, 8, 13);
  90. QUARTERROUND(3, 4, 9, 14);
  91. }
  92. if (is_endian.little) {
  93. for (i = 0; i < 16; ++i)
  94. output->u[i] = x[i] + input[i];
  95. } else {
  96. for (i = 0; i < 16; ++i)
  97. U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
  98. }
  99. }
  100. void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
  101. size_t len, const unsigned int key[8],
  102. const unsigned int counter[4])
  103. {
  104. u32 input[16];
  105. chacha_buf buf;
  106. size_t todo, i;
  107. /* sigma constant "expand 32-byte k" in little-endian encoding */
  108. input[0] = ((u32)'e') | ((u32)'x'<<8) | ((u32)'p'<<16) | ((u32)'a'<<24);
  109. input[1] = ((u32)'n') | ((u32)'d'<<8) | ((u32)' '<<16) | ((u32)'3'<<24);
  110. input[2] = ((u32)'2') | ((u32)'-'<<8) | ((u32)'b'<<16) | ((u32)'y'<<24);
  111. input[3] = ((u32)'t') | ((u32)'e'<<8) | ((u32)' '<<16) | ((u32)'k'<<24);
  112. input[4] = key[0];
  113. input[5] = key[1];
  114. input[6] = key[2];
  115. input[7] = key[3];
  116. input[8] = key[4];
  117. input[9] = key[5];
  118. input[10] = key[6];
  119. input[11] = key[7];
  120. input[12] = counter[0];
  121. input[13] = counter[1];
  122. input[14] = counter[2];
  123. input[15] = counter[3];
  124. while (len > 0) {
  125. todo = sizeof(buf);
  126. if (len < todo)
  127. todo = len;
  128. chacha20_core(&buf, input);
  129. for (i = 0; i < todo; i++)
  130. out[i] = inp[i] ^ buf.c[i];
  131. out += todo;
  132. inp += todo;
  133. len -= todo;
  134. /* advance counter */
  135. if (++input[12] == 0)
  136. input[13]++;
  137. }
  138. }