chacha20.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. // chacha20.go - A ChaCha stream cipher implementation.
  2. //
  3. // To the extent possible under law, Yawning Angel has waived all copyright
  4. // and related or neighboring rights to chacha20, using the Creative
  5. // Commons "CC0" public domain dedication. See LICENSE or
  6. // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
  7. package chacha20
  8. import (
  9. "crypto/cipher"
  10. "encoding/binary"
  11. "errors"
  12. "math"
  13. "runtime"
  14. "unsafe"
  15. )
  16. const (
  17. // KeySize is the ChaCha20 key size in bytes.
  18. KeySize = 32
  19. // NonceSize is the ChaCha20 nonce size in bytes.
  20. NonceSize = 8
  21. // INonceSize is the IETF ChaCha20 nonce size in bytes.
  22. INonceSize = 12
  23. // XNonceSize is the XChaCha20 nonce size in bytes.
  24. XNonceSize = 24
  25. // HNonceSize is the HChaCha20 nonce size in bytes.
  26. HNonceSize = 16
  27. // BlockSize is the ChaCha20 block size in bytes.
  28. BlockSize = 64
  29. stateSize = 16
  30. chachaRounds = 20
  31. // The constant "expand 32-byte k" as little endian uint32s.
  32. sigma0 = uint32(0x61707865)
  33. sigma1 = uint32(0x3320646e)
  34. sigma2 = uint32(0x79622d32)
  35. sigma3 = uint32(0x6b206574)
  36. )
  37. var (
  38. // ErrInvalidKey is the error returned when the key is invalid.
  39. ErrInvalidKey = errors.New("key length must be KeySize bytes")
  40. // ErrInvalidNonce is the error returned when the nonce is invalid.
  41. ErrInvalidNonce = errors.New("nonce length must be NonceSize/INonceSize/XNonceSize bytes")
  42. // ErrInvalidCounter is the error returned when the counter is invalid.
  43. ErrInvalidCounter = errors.New("block counter is invalid (out of range)")
  44. useUnsafe = false
  45. usingVectors = false
  46. blocksFn = blocksRef
  47. )
  48. // A Cipher is an instance of ChaCha20/XChaCha20 using a particular key and
  49. // nonce.
  50. type Cipher struct {
  51. state [stateSize]uint32
  52. buf [BlockSize]byte
  53. off int
  54. ietf bool
  55. }
  56. // Reset zeros the key data so that it will no longer appear in the process's
  57. // memory.
  58. func (c *Cipher) Reset() {
  59. for i := range c.state {
  60. c.state[i] = 0
  61. }
  62. for i := range c.buf {
  63. c.buf[i] = 0
  64. }
  65. }
  66. // XORKeyStream sets dst to the result of XORing src with the key stream. Dst
  67. // and src may be the same slice but otherwise should not overlap.
  68. func (c *Cipher) XORKeyStream(dst, src []byte) {
  69. if len(dst) < len(src) {
  70. src = src[:len(dst)]
  71. }
  72. for remaining := len(src); remaining > 0; {
  73. // Process multiple blocks at once.
  74. if c.off == BlockSize {
  75. nrBlocks := remaining / BlockSize
  76. directBytes := nrBlocks * BlockSize
  77. if nrBlocks > 0 {
  78. blocksFn(&c.state, src, dst, nrBlocks, c.ietf)
  79. remaining -= directBytes
  80. if remaining == 0 {
  81. return
  82. }
  83. dst = dst[directBytes:]
  84. src = src[directBytes:]
  85. }
  86. // If there's a partial block, generate 1 block of keystream into
  87. // the internal buffer.
  88. blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
  89. c.off = 0
  90. }
  91. // Process partial blocks from the buffered keystream.
  92. toXor := BlockSize - c.off
  93. if remaining < toXor {
  94. toXor = remaining
  95. }
  96. if toXor > 0 {
  97. for i, v := range src[:toXor] {
  98. dst[i] = v ^ c.buf[c.off+i]
  99. }
  100. dst = dst[toXor:]
  101. src = src[toXor:]
  102. remaining -= toXor
  103. c.off += toXor
  104. }
  105. }
  106. }
  107. // KeyStream sets dst to the raw keystream.
  108. func (c *Cipher) KeyStream(dst []byte) {
  109. for remaining := len(dst); remaining > 0; {
  110. // Process multiple blocks at once.
  111. if c.off == BlockSize {
  112. nrBlocks := remaining / BlockSize
  113. directBytes := nrBlocks * BlockSize
  114. if nrBlocks > 0 {
  115. blocksFn(&c.state, nil, dst, nrBlocks, c.ietf)
  116. remaining -= directBytes
  117. if remaining == 0 {
  118. return
  119. }
  120. dst = dst[directBytes:]
  121. }
  122. // If there's a partial block, generate 1 block of keystream into
  123. // the internal buffer.
  124. blocksFn(&c.state, nil, c.buf[:], 1, c.ietf)
  125. c.off = 0
  126. }
  127. // Process partial blocks from the buffered keystream.
  128. toCopy := BlockSize - c.off
  129. if remaining < toCopy {
  130. toCopy = remaining
  131. }
  132. if toCopy > 0 {
  133. copy(dst[:toCopy], c.buf[c.off:c.off+toCopy])
  134. dst = dst[toCopy:]
  135. remaining -= toCopy
  136. c.off += toCopy
  137. }
  138. }
  139. }
  140. // ReKey reinitializes the ChaCha20/XChaCha20 instance with the provided key
  141. // and nonce.
  142. func (c *Cipher) ReKey(key, nonce []byte) error {
  143. if len(key) != KeySize {
  144. return ErrInvalidKey
  145. }
  146. switch len(nonce) {
  147. case NonceSize:
  148. case INonceSize:
  149. case XNonceSize:
  150. var subkey [KeySize]byte
  151. var subnonce [HNonceSize]byte
  152. copy(subnonce[:], nonce[0:16])
  153. HChaCha(key, &subnonce, &subkey)
  154. key = subkey[:]
  155. nonce = nonce[16:24]
  156. defer func() {
  157. for i := range subkey {
  158. subkey[i] = 0
  159. }
  160. }()
  161. default:
  162. return ErrInvalidNonce
  163. }
  164. c.Reset()
  165. c.state[0] = sigma0
  166. c.state[1] = sigma1
  167. c.state[2] = sigma2
  168. c.state[3] = sigma3
  169. c.state[4] = binary.LittleEndian.Uint32(key[0:4])
  170. c.state[5] = binary.LittleEndian.Uint32(key[4:8])
  171. c.state[6] = binary.LittleEndian.Uint32(key[8:12])
  172. c.state[7] = binary.LittleEndian.Uint32(key[12:16])
  173. c.state[8] = binary.LittleEndian.Uint32(key[16:20])
  174. c.state[9] = binary.LittleEndian.Uint32(key[20:24])
  175. c.state[10] = binary.LittleEndian.Uint32(key[24:28])
  176. c.state[11] = binary.LittleEndian.Uint32(key[28:32])
  177. c.state[12] = 0
  178. if len(nonce) == INonceSize {
  179. c.state[13] = binary.LittleEndian.Uint32(nonce[0:4])
  180. c.state[14] = binary.LittleEndian.Uint32(nonce[4:8])
  181. c.state[15] = binary.LittleEndian.Uint32(nonce[8:12])
  182. c.ietf = true
  183. } else {
  184. c.state[13] = 0
  185. c.state[14] = binary.LittleEndian.Uint32(nonce[0:4])
  186. c.state[15] = binary.LittleEndian.Uint32(nonce[4:8])
  187. c.ietf = false
  188. }
  189. c.off = BlockSize
  190. return nil
  191. }
  192. // Seek sets the block counter to a given offset.
  193. func (c *Cipher) Seek(blockCounter uint64) error {
  194. if c.ietf {
  195. if blockCounter > math.MaxUint32 {
  196. return ErrInvalidCounter
  197. }
  198. c.state[12] = uint32(blockCounter)
  199. } else {
  200. c.state[12] = uint32(blockCounter)
  201. c.state[13] = uint32(blockCounter >> 32)
  202. }
  203. c.off = BlockSize
  204. return nil
  205. }
  206. // NewCipher returns a new ChaCha20/XChaCha20 instance.
  207. func NewCipher(key, nonce []byte) (*Cipher, error) {
  208. c := new(Cipher)
  209. if err := c.ReKey(key, nonce); err != nil {
  210. return nil, err
  211. }
  212. return c, nil
  213. }
  214. // HChaCha is the HChaCha20 hash function used to make XChaCha.
  215. func HChaCha(key []byte, nonce *[HNonceSize]byte, out *[32]byte) {
  216. var x [stateSize]uint32 // Last 4 slots unused, sigma hardcoded.
  217. x[0] = binary.LittleEndian.Uint32(key[0:4])
  218. x[1] = binary.LittleEndian.Uint32(key[4:8])
  219. x[2] = binary.LittleEndian.Uint32(key[8:12])
  220. x[3] = binary.LittleEndian.Uint32(key[12:16])
  221. x[4] = binary.LittleEndian.Uint32(key[16:20])
  222. x[5] = binary.LittleEndian.Uint32(key[20:24])
  223. x[6] = binary.LittleEndian.Uint32(key[24:28])
  224. x[7] = binary.LittleEndian.Uint32(key[28:32])
  225. x[8] = binary.LittleEndian.Uint32(nonce[0:4])
  226. x[9] = binary.LittleEndian.Uint32(nonce[4:8])
  227. x[10] = binary.LittleEndian.Uint32(nonce[8:12])
  228. x[11] = binary.LittleEndian.Uint32(nonce[12:16])
  229. hChaChaRef(&x, out)
  230. }
  231. func hChaChaRef(x *[stateSize]uint32, out *[32]byte) {
  232. x0, x1, x2, x3 := sigma0, sigma1, sigma2, sigma3
  233. x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11]
  234. for i := chachaRounds; i > 0; i -= 2 {
  235. // quarterround(x, 0, 4, 8, 12)
  236. x0 += x4
  237. x12 ^= x0
  238. x12 = (x12 << 16) | (x12 >> 16)
  239. x8 += x12
  240. x4 ^= x8
  241. x4 = (x4 << 12) | (x4 >> 20)
  242. x0 += x4
  243. x12 ^= x0
  244. x12 = (x12 << 8) | (x12 >> 24)
  245. x8 += x12
  246. x4 ^= x8
  247. x4 = (x4 << 7) | (x4 >> 25)
  248. // quarterround(x, 1, 5, 9, 13)
  249. x1 += x5
  250. x13 ^= x1
  251. x13 = (x13 << 16) | (x13 >> 16)
  252. x9 += x13
  253. x5 ^= x9
  254. x5 = (x5 << 12) | (x5 >> 20)
  255. x1 += x5
  256. x13 ^= x1
  257. x13 = (x13 << 8) | (x13 >> 24)
  258. x9 += x13
  259. x5 ^= x9
  260. x5 = (x5 << 7) | (x5 >> 25)
  261. // quarterround(x, 2, 6, 10, 14)
  262. x2 += x6
  263. x14 ^= x2
  264. x14 = (x14 << 16) | (x14 >> 16)
  265. x10 += x14
  266. x6 ^= x10
  267. x6 = (x6 << 12) | (x6 >> 20)
  268. x2 += x6
  269. x14 ^= x2
  270. x14 = (x14 << 8) | (x14 >> 24)
  271. x10 += x14
  272. x6 ^= x10
  273. x6 = (x6 << 7) | (x6 >> 25)
  274. // quarterround(x, 3, 7, 11, 15)
  275. x3 += x7
  276. x15 ^= x3
  277. x15 = (x15 << 16) | (x15 >> 16)
  278. x11 += x15
  279. x7 ^= x11
  280. x7 = (x7 << 12) | (x7 >> 20)
  281. x3 += x7
  282. x15 ^= x3
  283. x15 = (x15 << 8) | (x15 >> 24)
  284. x11 += x15
  285. x7 ^= x11
  286. x7 = (x7 << 7) | (x7 >> 25)
  287. // quarterround(x, 0, 5, 10, 15)
  288. x0 += x5
  289. x15 ^= x0
  290. x15 = (x15 << 16) | (x15 >> 16)
  291. x10 += x15
  292. x5 ^= x10
  293. x5 = (x5 << 12) | (x5 >> 20)
  294. x0 += x5
  295. x15 ^= x0
  296. x15 = (x15 << 8) | (x15 >> 24)
  297. x10 += x15
  298. x5 ^= x10
  299. x5 = (x5 << 7) | (x5 >> 25)
  300. // quarterround(x, 1, 6, 11, 12)
  301. x1 += x6
  302. x12 ^= x1
  303. x12 = (x12 << 16) | (x12 >> 16)
  304. x11 += x12
  305. x6 ^= x11
  306. x6 = (x6 << 12) | (x6 >> 20)
  307. x1 += x6
  308. x12 ^= x1
  309. x12 = (x12 << 8) | (x12 >> 24)
  310. x11 += x12
  311. x6 ^= x11
  312. x6 = (x6 << 7) | (x6 >> 25)
  313. // quarterround(x, 2, 7, 8, 13)
  314. x2 += x7
  315. x13 ^= x2
  316. x13 = (x13 << 16) | (x13 >> 16)
  317. x8 += x13
  318. x7 ^= x8
  319. x7 = (x7 << 12) | (x7 >> 20)
  320. x2 += x7
  321. x13 ^= x2
  322. x13 = (x13 << 8) | (x13 >> 24)
  323. x8 += x13
  324. x7 ^= x8
  325. x7 = (x7 << 7) | (x7 >> 25)
  326. // quarterround(x, 3, 4, 9, 14)
  327. x3 += x4
  328. x14 ^= x3
  329. x14 = (x14 << 16) | (x14 >> 16)
  330. x9 += x14
  331. x4 ^= x9
  332. x4 = (x4 << 12) | (x4 >> 20)
  333. x3 += x4
  334. x14 ^= x3
  335. x14 = (x14 << 8) | (x14 >> 24)
  336. x9 += x14
  337. x4 ^= x9
  338. x4 = (x4 << 7) | (x4 >> 25)
  339. }
  340. // HChaCha returns x0...x3 | x12...x15, which corresponds to the
  341. // indexes of the ChaCha constant and the indexes of the IV.
  342. if useUnsafe {
  343. outArr := (*[16]uint32)(unsafe.Pointer(&out[0]))
  344. outArr[0] = x0
  345. outArr[1] = x1
  346. outArr[2] = x2
  347. outArr[3] = x3
  348. outArr[4] = x12
  349. outArr[5] = x13
  350. outArr[6] = x14
  351. outArr[7] = x15
  352. } else {
  353. binary.LittleEndian.PutUint32(out[0:4], x0)
  354. binary.LittleEndian.PutUint32(out[4:8], x1)
  355. binary.LittleEndian.PutUint32(out[8:12], x2)
  356. binary.LittleEndian.PutUint32(out[12:16], x3)
  357. binary.LittleEndian.PutUint32(out[16:20], x12)
  358. binary.LittleEndian.PutUint32(out[20:24], x13)
  359. binary.LittleEndian.PutUint32(out[24:28], x14)
  360. binary.LittleEndian.PutUint32(out[28:32], x15)
  361. }
  362. return
  363. }
  364. func init() {
  365. switch runtime.GOARCH {
  366. case "386", "amd64":
  367. // Abuse unsafe to skip calling binary.LittleEndian.PutUint32
  368. // in the critical path. This is a big boost on systems that are
  369. // little endian and not overly picky about alignment.
  370. useUnsafe = true
  371. }
  372. }
  373. var _ cipher.Stream = (*Cipher)(nil)