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.

chacha_generic.go 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package ChaCha20 implements the core ChaCha20 function as specified
  5. // in https://tools.ietf.org/html/rfc7539#section-2.3.
  6. package chacha20
  7. import (
  8. "crypto/cipher"
  9. "encoding/binary"
  10. "golang.org/x/crypto/internal/subtle"
  11. )
  12. // assert that *Cipher implements cipher.Stream
  13. var _ cipher.Stream = (*Cipher)(nil)
  14. // Cipher is a stateful instance of ChaCha20 using a particular key
  15. // and nonce. A *Cipher implements the cipher.Stream interface.
  16. type Cipher struct {
  17. key [8]uint32
  18. counter uint32 // incremented after each block
  19. nonce [3]uint32
  20. buf [bufSize]byte // buffer for unused keystream bytes
  21. len int // number of unused keystream bytes at end of buf
  22. }
  23. // New creates a new ChaCha20 stream cipher with the given key and nonce.
  24. // The initial counter value is set to 0.
  25. func New(key [8]uint32, nonce [3]uint32) *Cipher {
  26. return &Cipher{key: key, nonce: nonce}
  27. }
  28. // ChaCha20 constants spelling "expand 32-byte k"
  29. const (
  30. j0 uint32 = 0x61707865
  31. j1 uint32 = 0x3320646e
  32. j2 uint32 = 0x79622d32
  33. j3 uint32 = 0x6b206574
  34. )
  35. func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
  36. a += b
  37. d ^= a
  38. d = (d << 16) | (d >> 16)
  39. c += d
  40. b ^= c
  41. b = (b << 12) | (b >> 20)
  42. a += b
  43. d ^= a
  44. d = (d << 8) | (d >> 24)
  45. c += d
  46. b ^= c
  47. b = (b << 7) | (b >> 25)
  48. return a, b, c, d
  49. }
  50. // XORKeyStream XORs each byte in the given slice with a byte from the
  51. // cipher's key stream. Dst and src must overlap entirely or not at all.
  52. //
  53. // If len(dst) < len(src), XORKeyStream will panic. It is acceptable
  54. // to pass a dst bigger than src, and in that case, XORKeyStream will
  55. // only update dst[:len(src)] and will not touch the rest of dst.
  56. //
  57. // Multiple calls to XORKeyStream behave as if the concatenation of
  58. // the src buffers was passed in a single run. That is, Cipher
  59. // maintains state and does not reset at each XORKeyStream call.
  60. func (s *Cipher) XORKeyStream(dst, src []byte) {
  61. if len(dst) < len(src) {
  62. panic("chacha20: output smaller than input")
  63. }
  64. if subtle.InexactOverlap(dst[:len(src)], src) {
  65. panic("chacha20: invalid buffer overlap")
  66. }
  67. // xor src with buffered keystream first
  68. if s.len != 0 {
  69. buf := s.buf[len(s.buf)-s.len:]
  70. if len(src) < len(buf) {
  71. buf = buf[:len(src)]
  72. }
  73. td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
  74. for i, b := range buf {
  75. td[i] = ts[i] ^ b
  76. }
  77. s.len -= len(buf)
  78. if s.len != 0 {
  79. return
  80. }
  81. s.buf = [len(s.buf)]byte{} // zero the empty buffer
  82. src = src[len(buf):]
  83. dst = dst[len(buf):]
  84. }
  85. if len(src) == 0 {
  86. return
  87. }
  88. if haveAsm {
  89. if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
  90. panic("chacha20: counter overflow")
  91. }
  92. s.xorKeyStreamAsm(dst, src)
  93. return
  94. }
  95. // set up a 64-byte buffer to pad out the final block if needed
  96. // (hoisted out of the main loop to avoid spills)
  97. rem := len(src) % 64 // length of final block
  98. fin := len(src) - rem // index of final block
  99. if rem > 0 {
  100. copy(s.buf[len(s.buf)-64:], src[fin:])
  101. }
  102. // pre-calculate most of the first round
  103. s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
  104. s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
  105. s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
  106. n := len(src)
  107. src, dst = src[:n:n], dst[:n:n] // BCE hint
  108. for i := 0; i < n; i += 64 {
  109. // calculate the remainder of the first round
  110. s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
  111. // execute the second round
  112. x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
  113. x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
  114. x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
  115. x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
  116. // execute the remaining 18 rounds
  117. for i := 0; i < 9; i++ {
  118. x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
  119. x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
  120. x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
  121. x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
  122. x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
  123. x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
  124. x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
  125. x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
  126. }
  127. x0 += j0
  128. x1 += j1
  129. x2 += j2
  130. x3 += j3
  131. x4 += s.key[0]
  132. x5 += s.key[1]
  133. x6 += s.key[2]
  134. x7 += s.key[3]
  135. x8 += s.key[4]
  136. x9 += s.key[5]
  137. x10 += s.key[6]
  138. x11 += s.key[7]
  139. x12 += s.counter
  140. x13 += s.nonce[0]
  141. x14 += s.nonce[1]
  142. x15 += s.nonce[2]
  143. // increment the counter
  144. s.counter += 1
  145. if s.counter == 0 {
  146. panic("chacha20: counter overflow")
  147. }
  148. // pad to 64 bytes if needed
  149. in, out := src[i:], dst[i:]
  150. if i == fin {
  151. // src[fin:] has already been copied into s.buf before
  152. // the main loop
  153. in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
  154. }
  155. in, out = in[:64], out[:64] // BCE hint
  156. // XOR the key stream with the source and write out the result
  157. xor(out[0:], in[0:], x0)
  158. xor(out[4:], in[4:], x1)
  159. xor(out[8:], in[8:], x2)
  160. xor(out[12:], in[12:], x3)
  161. xor(out[16:], in[16:], x4)
  162. xor(out[20:], in[20:], x5)
  163. xor(out[24:], in[24:], x6)
  164. xor(out[28:], in[28:], x7)
  165. xor(out[32:], in[32:], x8)
  166. xor(out[36:], in[36:], x9)
  167. xor(out[40:], in[40:], x10)
  168. xor(out[44:], in[44:], x11)
  169. xor(out[48:], in[48:], x12)
  170. xor(out[52:], in[52:], x13)
  171. xor(out[56:], in[56:], x14)
  172. xor(out[60:], in[60:], x15)
  173. }
  174. // copy any trailing bytes out of the buffer and into dst
  175. if rem != 0 {
  176. s.len = 64 - rem
  177. copy(dst[fin:], s.buf[len(s.buf)-64:])
  178. }
  179. }
  180. // Advance discards bytes in the key stream until the next 64 byte block
  181. // boundary is reached and updates the counter accordingly. If the key
  182. // stream is already at a block boundary no bytes will be discarded and
  183. // the counter will be unchanged.
  184. func (s *Cipher) Advance() {
  185. s.len -= s.len % 64
  186. if s.len == 0 {
  187. s.buf = [len(s.buf)]byte{}
  188. }
  189. }
  190. // XORKeyStream crypts bytes from in to out using the given key and counters.
  191. // In and out must overlap entirely or not at all. Counter contains the raw
  192. // ChaCha20 counter bytes (i.e. block counter followed by nonce).
  193. func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
  194. s := Cipher{
  195. key: [8]uint32{
  196. binary.LittleEndian.Uint32(key[0:4]),
  197. binary.LittleEndian.Uint32(key[4:8]),
  198. binary.LittleEndian.Uint32(key[8:12]),
  199. binary.LittleEndian.Uint32(key[12:16]),
  200. binary.LittleEndian.Uint32(key[16:20]),
  201. binary.LittleEndian.Uint32(key[20:24]),
  202. binary.LittleEndian.Uint32(key[24:28]),
  203. binary.LittleEndian.Uint32(key[28:32]),
  204. },
  205. nonce: [3]uint32{
  206. binary.LittleEndian.Uint32(counter[4:8]),
  207. binary.LittleEndian.Uint32(counter[8:12]),
  208. binary.LittleEndian.Uint32(counter[12:16]),
  209. },
  210. counter: binary.LittleEndian.Uint32(counter[0:4]),
  211. }
  212. s.XORKeyStream(out, in)
  213. }
  214. // HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
  215. // nonce. It should only be used as part of the XChaCha20 construction.
  216. func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
  217. x0, x1, x2, x3 := j0, j1, j2, j3
  218. x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
  219. x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
  220. x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
  221. for i := 0; i < 10; i++ {
  222. x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
  223. x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
  224. x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
  225. x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
  226. x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
  227. x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
  228. x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
  229. x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
  230. }
  231. var out [8]uint32
  232. out[0], out[1], out[2], out[3] = x0, x1, x2, x3
  233. out[4], out[5], out[6], out[7] = x12, x13, x14, x15
  234. return out
  235. }