chacha_enc.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. /* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
  10. #include <string.h>
  11. #include "internal/endian.h"
  12. #include "crypto/chacha.h"
  13. #include "crypto/ctype.h"
  14. typedef unsigned int u32;
  15. typedef unsigned char u8;
  16. typedef union {
  17. u32 u[16];
  18. u8 c[64];
  19. } chacha_buf;
  20. # define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
  21. # ifndef PEDANTIC
  22. # if defined(__GNUC__) && __GNUC__>=2 && \
  23. !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
  24. # if defined(__riscv_zbb) || defined(__riscv_zbkb)
  25. # if __riscv_xlen == 64
  26. # undef ROTATE
  27. # define ROTATE(x, n) ({ u32 ret; \
  28. asm ("roriw %0, %1, %2" \
  29. : "=r"(ret) \
  30. : "r"(x), "i"(32 - (n))); ret;})
  31. # endif
  32. # if __riscv_xlen == 32
  33. # undef ROTATE
  34. # define ROTATE(x, n) ({ u32 ret; \
  35. asm ("rori %0, %1, %2" \
  36. : "=r"(ret) \
  37. : "r"(x), "i"(32 - (n))); ret;})
  38. # endif
  39. # endif
  40. # endif
  41. # endif
  42. # define U32TO8_LITTLE(p, v) do { \
  43. (p)[0] = (u8)(v >> 0); \
  44. (p)[1] = (u8)(v >> 8); \
  45. (p)[2] = (u8)(v >> 16); \
  46. (p)[3] = (u8)(v >> 24); \
  47. } while(0)
  48. /* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
  49. # define QUARTERROUND(a,b,c,d) ( \
  50. x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]),16), \
  51. x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]),12), \
  52. x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 8), \
  53. x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 7) )
  54. /* chacha_core performs 20 rounds of ChaCha on the input words in
  55. * |input| and writes the 64 output bytes to |output|. */
  56. static void chacha20_core(chacha_buf *output, const u32 input[16])
  57. {
  58. u32 x[16];
  59. int i;
  60. DECLARE_IS_ENDIAN;
  61. memcpy(x, input, sizeof(x));
  62. for (i = 20; i > 0; i -= 2) {
  63. QUARTERROUND(0, 4, 8, 12);
  64. QUARTERROUND(1, 5, 9, 13);
  65. QUARTERROUND(2, 6, 10, 14);
  66. QUARTERROUND(3, 7, 11, 15);
  67. QUARTERROUND(0, 5, 10, 15);
  68. QUARTERROUND(1, 6, 11, 12);
  69. QUARTERROUND(2, 7, 8, 13);
  70. QUARTERROUND(3, 4, 9, 14);
  71. }
  72. if (IS_LITTLE_ENDIAN) {
  73. for (i = 0; i < 16; ++i)
  74. output->u[i] = x[i] + input[i];
  75. } else {
  76. for (i = 0; i < 16; ++i)
  77. U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
  78. }
  79. }
  80. void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
  81. size_t len, const unsigned int key[8],
  82. const unsigned int counter[4])
  83. {
  84. u32 input[16];
  85. chacha_buf buf;
  86. size_t todo, i;
  87. /* sigma constant "expand 32-byte k" in little-endian encoding */
  88. input[0] = ((u32)ossl_toascii('e')) | ((u32)ossl_toascii('x') << 8)
  89. | ((u32)ossl_toascii('p') << 16)
  90. | ((u32)ossl_toascii('a') << 24);
  91. input[1] = ((u32)ossl_toascii('n')) | ((u32)ossl_toascii('d') << 8)
  92. | ((u32)ossl_toascii(' ') << 16)
  93. | ((u32)ossl_toascii('3') << 24);
  94. input[2] = ((u32)ossl_toascii('2')) | ((u32)ossl_toascii('-') << 8)
  95. | ((u32)ossl_toascii('b') << 16)
  96. | ((u32)ossl_toascii('y') << 24);
  97. input[3] = ((u32)ossl_toascii('t')) | ((u32)ossl_toascii('e') << 8)
  98. | ((u32)ossl_toascii(' ') << 16)
  99. | ((u32)ossl_toascii('k') << 24);
  100. input[4] = key[0];
  101. input[5] = key[1];
  102. input[6] = key[2];
  103. input[7] = key[3];
  104. input[8] = key[4];
  105. input[9] = key[5];
  106. input[10] = key[6];
  107. input[11] = key[7];
  108. input[12] = counter[0];
  109. input[13] = counter[1];
  110. input[14] = counter[2];
  111. input[15] = counter[3];
  112. while (len > 0) {
  113. todo = sizeof(buf);
  114. if (len < todo)
  115. todo = len;
  116. chacha20_core(&buf, input);
  117. for (i = 0; i < todo; i++)
  118. out[i] = inp[i] ^ buf.c[i];
  119. out += todo;
  120. inp += todo;
  121. len -= todo;
  122. /*
  123. * Advance 32-bit counter. Note that as subroutine is so to
  124. * say nonce-agnostic, this limited counter width doesn't
  125. * prevent caller from implementing wider counter. It would
  126. * simply take two calls split on counter overflow...
  127. */
  128. input[12]++;
  129. }
  130. }