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.
 
 
 

237 lines
6.5 KiB

  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. // XORKeyStream XORs each byte in the given slice with a byte from the
  29. // cipher's key stream. Dst and src must overlap entirely or not at all.
  30. //
  31. // If len(dst) < len(src), XORKeyStream will panic. It is acceptable
  32. // to pass a dst bigger than src, and in that case, XORKeyStream will
  33. // only update dst[:len(src)] and will not touch the rest of dst.
  34. //
  35. // Multiple calls to XORKeyStream behave as if the concatenation of
  36. // the src buffers was passed in a single run. That is, Cipher
  37. // maintains state and does not reset at each XORKeyStream call.
  38. func (s *Cipher) XORKeyStream(dst, src []byte) {
  39. if len(dst) < len(src) {
  40. panic("chacha20: output smaller than input")
  41. }
  42. if subtle.InexactOverlap(dst[:len(src)], src) {
  43. panic("chacha20: invalid buffer overlap")
  44. }
  45. // xor src with buffered keystream first
  46. if s.len != 0 {
  47. buf := s.buf[len(s.buf)-s.len:]
  48. if len(src) < len(buf) {
  49. buf = buf[:len(src)]
  50. }
  51. td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
  52. for i, b := range buf {
  53. td[i] = ts[i] ^ b
  54. }
  55. s.len -= len(buf)
  56. if s.len != 0 {
  57. return
  58. }
  59. s.buf = [len(s.buf)]byte{} // zero the empty buffer
  60. src = src[len(buf):]
  61. dst = dst[len(buf):]
  62. }
  63. if len(src) == 0 {
  64. return
  65. }
  66. if haveAsm {
  67. s.xorKeyStreamAsm(dst, src)
  68. return
  69. }
  70. // set up a 64-byte buffer to pad out the final block if needed
  71. // (hoisted out of the main loop to avoid spills)
  72. rem := len(src) % 64 // length of final block
  73. fin := len(src) - rem // index of final block
  74. if rem > 0 {
  75. copy(s.buf[len(s.buf)-64:], src[fin:])
  76. }
  77. // qr calculates a quarter round
  78. qr := func(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
  79. a += b
  80. d ^= a
  81. d = (d << 16) | (d >> 16)
  82. c += d
  83. b ^= c
  84. b = (b << 12) | (b >> 20)
  85. a += b
  86. d ^= a
  87. d = (d << 8) | (d >> 24)
  88. c += d
  89. b ^= c
  90. b = (b << 7) | (b >> 25)
  91. return a, b, c, d
  92. }
  93. // ChaCha20 constants
  94. const (
  95. j0 = 0x61707865
  96. j1 = 0x3320646e
  97. j2 = 0x79622d32
  98. j3 = 0x6b206574
  99. )
  100. // pre-calculate most of the first round
  101. s1, s5, s9, s13 := qr(j1, s.key[1], s.key[5], s.nonce[0])
  102. s2, s6, s10, s14 := qr(j2, s.key[2], s.key[6], s.nonce[1])
  103. s3, s7, s11, s15 := qr(j3, s.key[3], s.key[7], s.nonce[2])
  104. n := len(src)
  105. src, dst = src[:n:n], dst[:n:n] // BCE hint
  106. for i := 0; i < n; i += 64 {
  107. // calculate the remainder of the first round
  108. s0, s4, s8, s12 := qr(j0, s.key[0], s.key[4], s.counter)
  109. // execute the second round
  110. x0, x5, x10, x15 := qr(s0, s5, s10, s15)
  111. x1, x6, x11, x12 := qr(s1, s6, s11, s12)
  112. x2, x7, x8, x13 := qr(s2, s7, s8, s13)
  113. x3, x4, x9, x14 := qr(s3, s4, s9, s14)
  114. // execute the remaining 18 rounds
  115. for i := 0; i < 9; i++ {
  116. x0, x4, x8, x12 = qr(x0, x4, x8, x12)
  117. x1, x5, x9, x13 = qr(x1, x5, x9, x13)
  118. x2, x6, x10, x14 = qr(x2, x6, x10, x14)
  119. x3, x7, x11, x15 = qr(x3, x7, x11, x15)
  120. x0, x5, x10, x15 = qr(x0, x5, x10, x15)
  121. x1, x6, x11, x12 = qr(x1, x6, x11, x12)
  122. x2, x7, x8, x13 = qr(x2, x7, x8, x13)
  123. x3, x4, x9, x14 = qr(x3, x4, x9, x14)
  124. }
  125. x0 += j0
  126. x1 += j1
  127. x2 += j2
  128. x3 += j3
  129. x4 += s.key[0]
  130. x5 += s.key[1]
  131. x6 += s.key[2]
  132. x7 += s.key[3]
  133. x8 += s.key[4]
  134. x9 += s.key[5]
  135. x10 += s.key[6]
  136. x11 += s.key[7]
  137. x12 += s.counter
  138. x13 += s.nonce[0]
  139. x14 += s.nonce[1]
  140. x15 += s.nonce[2]
  141. // increment the counter
  142. s.counter += 1
  143. if s.counter == 0 {
  144. panic("chacha20: counter overflow")
  145. }
  146. // pad to 64 bytes if needed
  147. in, out := src[i:], dst[i:]
  148. if i == fin {
  149. // src[fin:] has already been copied into s.buf before
  150. // the main loop
  151. in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
  152. }
  153. in, out = in[:64], out[:64] // BCE hint
  154. // XOR the key stream with the source and write out the result
  155. xor(out[0:], in[0:], x0)
  156. xor(out[4:], in[4:], x1)
  157. xor(out[8:], in[8:], x2)
  158. xor(out[12:], in[12:], x3)
  159. xor(out[16:], in[16:], x4)
  160. xor(out[20:], in[20:], x5)
  161. xor(out[24:], in[24:], x6)
  162. xor(out[28:], in[28:], x7)
  163. xor(out[32:], in[32:], x8)
  164. xor(out[36:], in[36:], x9)
  165. xor(out[40:], in[40:], x10)
  166. xor(out[44:], in[44:], x11)
  167. xor(out[48:], in[48:], x12)
  168. xor(out[52:], in[52:], x13)
  169. xor(out[56:], in[56:], x14)
  170. xor(out[60:], in[60:], x15)
  171. }
  172. // copy any trailing bytes out of the buffer and into dst
  173. if rem != 0 {
  174. s.len = 64 - rem
  175. copy(dst[fin:], s.buf[len(s.buf)-64:])
  176. }
  177. }
  178. // Advance discards bytes in the key stream until the next 64 byte block
  179. // boundary is reached and updates the counter accordingly. If the key
  180. // stream is already at a block boundary no bytes will be discarded and
  181. // the counter will be unchanged.
  182. func (s *Cipher) Advance() {
  183. s.len -= s.len % 64
  184. if s.len == 0 {
  185. s.buf = [len(s.buf)]byte{}
  186. }
  187. }
  188. // XORKeyStream crypts bytes from in to out using the given key and counters.
  189. // In and out must overlap entirely or not at all. Counter contains the raw
  190. // ChaCha20 counter bytes (i.e. block counter followed by nonce).
  191. func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
  192. s := Cipher{
  193. key: [8]uint32{
  194. binary.LittleEndian.Uint32(key[0:4]),
  195. binary.LittleEndian.Uint32(key[4:8]),
  196. binary.LittleEndian.Uint32(key[8:12]),
  197. binary.LittleEndian.Uint32(key[12:16]),
  198. binary.LittleEndian.Uint32(key[16:20]),
  199. binary.LittleEndian.Uint32(key[20:24]),
  200. binary.LittleEndian.Uint32(key[24:28]),
  201. binary.LittleEndian.Uint32(key[28:32]),
  202. },
  203. nonce: [3]uint32{
  204. binary.LittleEndian.Uint32(counter[4:8]),
  205. binary.LittleEndian.Uint32(counter[8:12]),
  206. binary.LittleEndian.Uint32(counter[12:16]),
  207. },
  208. counter: binary.LittleEndian.Uint32(counter[0:4]),
  209. }
  210. s.XORKeyStream(out, in)
  211. }