chacha_generic.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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 ChaCha20 and XChaCha20 encryption algorithms
  5. // as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
  6. package chacha20
  7. import (
  8. "crypto/cipher"
  9. "encoding/binary"
  10. "errors"
  11. "math/bits"
  12. "golang.org/x/crypto/internal/subtle"
  13. )
  14. const (
  15. // KeySize is the size of the key used by this cipher, in bytes.
  16. KeySize = 32
  17. // NonceSize is the size of the nonce used with the standard variant of this
  18. // cipher, in bytes.
  19. //
  20. // Note that this is too short to be safely generated at random if the same
  21. // key is reused more than 2³² times.
  22. NonceSize = 12
  23. // NonceSizeX is the size of the nonce used with the XChaCha20 variant of
  24. // this cipher, in bytes.
  25. NonceSizeX = 24
  26. )
  27. // Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
  28. // and nonce. A *Cipher implements the cipher.Stream interface.
  29. type Cipher struct {
  30. // The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
  31. // (incremented after each block), and 3 of nonce.
  32. key [8]uint32
  33. counter uint32
  34. nonce [3]uint32
  35. // The last len bytes of buf are leftover key stream bytes from the previous
  36. // XORKeyStream invocation. The size of buf depends on how many blocks are
  37. // computed at a time.
  38. buf [bufSize]byte
  39. len int
  40. // The counter-independent results of the first round are cached after they
  41. // are computed the first time.
  42. precompDone bool
  43. p1, p5, p9, p13 uint32
  44. p2, p6, p10, p14 uint32
  45. p3, p7, p11, p15 uint32
  46. }
  47. var _ cipher.Stream = (*Cipher)(nil)
  48. // NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
  49. // 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
  50. // the XChaCha20 construction will be used. It returns an error if key or nonce
  51. // have any other length.
  52. //
  53. // Note that ChaCha20, like all stream ciphers, is not authenticated and allows
  54. // attackers to silently tamper with the plaintext. For this reason, it is more
  55. // appropriate as a building block than as a standalone encryption mechanism.
  56. // Instead, consider using package golang.org/x/crypto/chacha20poly1305.
  57. func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
  58. // This function is split into a wrapper so that the Cipher allocation will
  59. // be inlined, and depending on how the caller uses the return value, won't
  60. // escape to the heap.
  61. c := &Cipher{}
  62. return newUnauthenticatedCipher(c, key, nonce)
  63. }
  64. func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
  65. if len(key) != KeySize {
  66. return nil, errors.New("chacha20: wrong key size")
  67. }
  68. if len(nonce) == NonceSizeX {
  69. // XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
  70. // derived key, allowing it to operate on a nonce of 24 bytes. See
  71. // draft-irtf-cfrg-xchacha-01, Section 2.3.
  72. key, _ = HChaCha20(key, nonce[0:16])
  73. cNonce := make([]byte, NonceSize)
  74. copy(cNonce[4:12], nonce[16:24])
  75. nonce = cNonce
  76. } else if len(nonce) != NonceSize {
  77. return nil, errors.New("chacha20: wrong nonce size")
  78. }
  79. c.key = [8]uint32{
  80. binary.LittleEndian.Uint32(key[0:4]),
  81. binary.LittleEndian.Uint32(key[4:8]),
  82. binary.LittleEndian.Uint32(key[8:12]),
  83. binary.LittleEndian.Uint32(key[12:16]),
  84. binary.LittleEndian.Uint32(key[16:20]),
  85. binary.LittleEndian.Uint32(key[20:24]),
  86. binary.LittleEndian.Uint32(key[24:28]),
  87. binary.LittleEndian.Uint32(key[28:32]),
  88. }
  89. c.nonce = [3]uint32{
  90. binary.LittleEndian.Uint32(nonce[0:4]),
  91. binary.LittleEndian.Uint32(nonce[4:8]),
  92. binary.LittleEndian.Uint32(nonce[8:12]),
  93. }
  94. return c, nil
  95. }
  96. // The constant first 4 words of the ChaCha20 state.
  97. const (
  98. j0 uint32 = 0x61707865 // expa
  99. j1 uint32 = 0x3320646e // nd 3
  100. j2 uint32 = 0x79622d32 // 2-by
  101. j3 uint32 = 0x6b206574 // te k
  102. )
  103. const blockSize = 64
  104. // quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
  105. // It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
  106. // words each round, in columnar or diagonal groups of 4 at a time.
  107. func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
  108. a += b
  109. d ^= a
  110. d = bits.RotateLeft32(d, 16)
  111. c += d
  112. b ^= c
  113. b = bits.RotateLeft32(b, 12)
  114. a += b
  115. d ^= a
  116. d = bits.RotateLeft32(d, 8)
  117. c += d
  118. b ^= c
  119. b = bits.RotateLeft32(b, 7)
  120. return a, b, c, d
  121. }
  122. // XORKeyStream XORs each byte in the given slice with a byte from the
  123. // cipher's key stream. Dst and src must overlap entirely or not at all.
  124. //
  125. // If len(dst) < len(src), XORKeyStream will panic. It is acceptable
  126. // to pass a dst bigger than src, and in that case, XORKeyStream will
  127. // only update dst[:len(src)] and will not touch the rest of dst.
  128. //
  129. // Multiple calls to XORKeyStream behave as if the concatenation of
  130. // the src buffers was passed in a single run. That is, Cipher
  131. // maintains state and does not reset at each XORKeyStream call.
  132. func (s *Cipher) XORKeyStream(dst, src []byte) {
  133. if len(src) == 0 {
  134. return
  135. }
  136. if len(dst) < len(src) {
  137. panic("chacha20: output smaller than input")
  138. }
  139. dst = dst[:len(src)]
  140. if subtle.InexactOverlap(dst, src) {
  141. panic("chacha20: invalid buffer overlap")
  142. }
  143. // First, drain any remaining key stream from a previous XORKeyStream.
  144. if s.len != 0 {
  145. keyStream := s.buf[bufSize-s.len:]
  146. if len(src) < len(keyStream) {
  147. keyStream = keyStream[:len(src)]
  148. }
  149. _ = src[len(keyStream)-1] // bounds check elimination hint
  150. for i, b := range keyStream {
  151. dst[i] = src[i] ^ b
  152. }
  153. s.len -= len(keyStream)
  154. src = src[len(keyStream):]
  155. dst = dst[len(keyStream):]
  156. }
  157. const blocksPerBuf = bufSize / blockSize
  158. numBufs := (uint64(len(src)) + bufSize - 1) / bufSize
  159. if uint64(s.counter)+numBufs*blocksPerBuf >= 1<<32 {
  160. panic("chacha20: counter overflow")
  161. }
  162. // xorKeyStreamBlocks implementations expect input lengths that are a
  163. // multiple of bufSize. Platform-specific ones process multiple blocks at a
  164. // time, so have bufSizes that are a multiple of blockSize.
  165. rem := len(src) % bufSize
  166. full := len(src) - rem
  167. if full > 0 {
  168. s.xorKeyStreamBlocks(dst[:full], src[:full])
  169. }
  170. // If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
  171. // keep the leftover keystream for the next XORKeyStream invocation.
  172. if rem > 0 {
  173. s.buf = [bufSize]byte{}
  174. copy(s.buf[:], src[full:])
  175. s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
  176. s.len = bufSize - copy(dst[full:], s.buf[:])
  177. }
  178. }
  179. func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
  180. if len(dst) != len(src) || len(dst)%blockSize != 0 {
  181. panic("chacha20: internal error: wrong dst and/or src length")
  182. }
  183. // To generate each block of key stream, the initial cipher state
  184. // (represented below) is passed through 20 rounds of shuffling,
  185. // alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
  186. // or by diagonals (like 1, 6, 11, 12).
  187. //
  188. // 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
  189. // 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
  190. // 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
  191. // 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
  192. //
  193. // c=constant k=key b=blockcount n=nonce
  194. var (
  195. c0, c1, c2, c3 = j0, j1, j2, j3
  196. c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3]
  197. c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
  198. _, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
  199. )
  200. // Three quarters of the first round don't depend on the counter, so we can
  201. // calculate them here, and reuse them for multiple blocks in the loop, and
  202. // for future XORKeyStream invocations.
  203. if !s.precompDone {
  204. s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
  205. s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
  206. s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
  207. s.precompDone = true
  208. }
  209. for i := 0; i < len(src); i += blockSize {
  210. // The remainder of the first column round.
  211. fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
  212. // The second diagonal round.
  213. x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
  214. x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
  215. x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
  216. x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)
  217. // The remaining 18 rounds.
  218. for i := 0; i < 9; i++ {
  219. // Column round.
  220. x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
  221. x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
  222. x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
  223. x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
  224. // Diagonal round.
  225. x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
  226. x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
  227. x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
  228. x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
  229. }
  230. // Finally, add back the initial state to generate the key stream.
  231. x0 += c0
  232. x1 += c1
  233. x2 += c2
  234. x3 += c3
  235. x4 += c4
  236. x5 += c5
  237. x6 += c6
  238. x7 += c7
  239. x8 += c8
  240. x9 += c9
  241. x10 += c10
  242. x11 += c11
  243. x12 += s.counter
  244. x13 += c13
  245. x14 += c14
  246. x15 += c15
  247. s.counter += 1
  248. if s.counter == 0 {
  249. panic("chacha20: internal error: counter overflow")
  250. }
  251. in, out := src[i:], dst[i:]
  252. in, out = in[:blockSize], out[:blockSize] // bounds check elimination hint
  253. // XOR the key stream with the source and write out the result.
  254. xor(out[0:], in[0:], x0)
  255. xor(out[4:], in[4:], x1)
  256. xor(out[8:], in[8:], x2)
  257. xor(out[12:], in[12:], x3)
  258. xor(out[16:], in[16:], x4)
  259. xor(out[20:], in[20:], x5)
  260. xor(out[24:], in[24:], x6)
  261. xor(out[28:], in[28:], x7)
  262. xor(out[32:], in[32:], x8)
  263. xor(out[36:], in[36:], x9)
  264. xor(out[40:], in[40:], x10)
  265. xor(out[44:], in[44:], x11)
  266. xor(out[48:], in[48:], x12)
  267. xor(out[52:], in[52:], x13)
  268. xor(out[56:], in[56:], x14)
  269. xor(out[60:], in[60:], x15)
  270. }
  271. }
  272. // HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
  273. // key and a 16 bytes nonce. It returns an error if key or nonce have any other
  274. // length. It is used as part of the XChaCha20 construction.
  275. func HChaCha20(key, nonce []byte) ([]byte, error) {
  276. // This function is split into a wrapper so that the slice allocation will
  277. // be inlined, and depending on how the caller uses the return value, won't
  278. // escape to the heap.
  279. out := make([]byte, 32)
  280. return hChaCha20(out, key, nonce)
  281. }
  282. func hChaCha20(out, key, nonce []byte) ([]byte, error) {
  283. if len(key) != KeySize {
  284. return nil, errors.New("chacha20: wrong HChaCha20 key size")
  285. }
  286. if len(nonce) != 16 {
  287. return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
  288. }
  289. x0, x1, x2, x3 := j0, j1, j2, j3
  290. x4 := binary.LittleEndian.Uint32(key[0:4])
  291. x5 := binary.LittleEndian.Uint32(key[4:8])
  292. x6 := binary.LittleEndian.Uint32(key[8:12])
  293. x7 := binary.LittleEndian.Uint32(key[12:16])
  294. x8 := binary.LittleEndian.Uint32(key[16:20])
  295. x9 := binary.LittleEndian.Uint32(key[20:24])
  296. x10 := binary.LittleEndian.Uint32(key[24:28])
  297. x11 := binary.LittleEndian.Uint32(key[28:32])
  298. x12 := binary.LittleEndian.Uint32(nonce[0:4])
  299. x13 := binary.LittleEndian.Uint32(nonce[4:8])
  300. x14 := binary.LittleEndian.Uint32(nonce[8:12])
  301. x15 := binary.LittleEndian.Uint32(nonce[12:16])
  302. for i := 0; i < 10; i++ {
  303. // Diagonal round.
  304. x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
  305. x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
  306. x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
  307. x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
  308. // Column round.
  309. x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
  310. x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
  311. x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
  312. x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
  313. }
  314. _ = out[31] // bounds check elimination hint
  315. binary.LittleEndian.PutUint32(out[0:4], x0)
  316. binary.LittleEndian.PutUint32(out[4:8], x1)
  317. binary.LittleEndian.PutUint32(out[8:12], x2)
  318. binary.LittleEndian.PutUint32(out[12:16], x3)
  319. binary.LittleEndian.PutUint32(out[16:20], x12)
  320. binary.LittleEndian.PutUint32(out[20:24], x13)
  321. binary.LittleEndian.PutUint32(out[24:28], x14)
  322. binary.LittleEndian.PutUint32(out[28:32], x15)
  323. return out, nil
  324. }