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.
5 // Package ChaCha20 implements the core ChaCha20 function as specified
6 // in https://tools.ietf.org/html/rfc7539#section-2.3.
13 "golang.org/x/crypto/internal/subtle"
16 // assert that *Cipher implements cipher.Stream
17 var _ cipher.Stream = (*Cipher)(nil)
19 // Cipher is a stateful instance of ChaCha20 using a particular key
20 // and nonce. A *Cipher implements the cipher.Stream interface.
23 counter uint32 // incremented after each block
25 buf [bufSize]byte // buffer for unused keystream bytes
26 len int // number of unused keystream bytes at end of buf
29 // New creates a new ChaCha20 stream cipher with the given key and nonce.
30 // The initial counter value is set to 0.
31 func New(key [8]uint32, nonce [3]uint32) *Cipher {
32 return &Cipher{key: key, nonce: nonce}
35 // ChaCha20 constants spelling "expand 32-byte k"
37 j0 uint32 = 0x61707865
38 j1 uint32 = 0x3320646e
39 j2 uint32 = 0x79622d32
40 j3 uint32 = 0x6b206574
43 func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
46 d = (d << 16) | (d >> 16)
49 b = (b << 12) | (b >> 20)
52 d = (d << 8) | (d >> 24)
55 b = (b << 7) | (b >> 25)
59 // XORKeyStream XORs each byte in the given slice with a byte from the
60 // cipher's key stream. Dst and src must overlap entirely or not at all.
62 // If len(dst) < len(src), XORKeyStream will panic. It is acceptable
63 // to pass a dst bigger than src, and in that case, XORKeyStream will
64 // only update dst[:len(src)] and will not touch the rest of dst.
66 // Multiple calls to XORKeyStream behave as if the concatenation of
67 // the src buffers was passed in a single run. That is, Cipher
68 // maintains state and does not reset at each XORKeyStream call.
69 func (s *Cipher) XORKeyStream(dst, src []byte) {
70 if len(dst) < len(src) {
71 panic("chacha20: output smaller than input")
73 if subtle.InexactOverlap(dst[:len(src)], src) {
74 panic("chacha20: invalid buffer overlap")
77 // xor src with buffered keystream first
79 buf := s.buf[len(s.buf)-s.len:]
80 if len(src) < len(buf) {
83 td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
84 for i, b := range buf {
91 s.buf = [len(s.buf)]byte{} // zero the empty buffer
100 if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
101 panic("chacha20: counter overflow")
103 s.xorKeyStreamAsm(dst, src)
107 // set up a 64-byte buffer to pad out the final block if needed
108 // (hoisted out of the main loop to avoid spills)
109 rem := len(src) % 64 // length of final block
110 fin := len(src) - rem // index of final block
112 copy(s.buf[len(s.buf)-64:], src[fin:])
115 // pre-calculate most of the first round
116 s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
117 s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
118 s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
121 src, dst = src[:n:n], dst[:n:n] // BCE hint
122 for i := 0; i < n; i += 64 {
123 // calculate the remainder of the first round
124 s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
126 // execute the second round
127 x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
128 x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
129 x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
130 x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
132 // execute the remaining 18 rounds
133 for i := 0; i < 9; i++ {
134 x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
135 x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
136 x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
137 x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
139 x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
140 x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
141 x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
142 x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
164 // increment the counter
167 panic("chacha20: counter overflow")
170 // pad to 64 bytes if needed
171 in, out := src[i:], dst[i:]
173 // src[fin:] has already been copied into s.buf before
175 in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
177 in, out = in[:64], out[:64] // BCE hint
179 // XOR the key stream with the source and write out the result
180 xor(out[0:], in[0:], x0)
181 xor(out[4:], in[4:], x1)
182 xor(out[8:], in[8:], x2)
183 xor(out[12:], in[12:], x3)
184 xor(out[16:], in[16:], x4)
185 xor(out[20:], in[20:], x5)
186 xor(out[24:], in[24:], x6)
187 xor(out[28:], in[28:], x7)
188 xor(out[32:], in[32:], x8)
189 xor(out[36:], in[36:], x9)
190 xor(out[40:], in[40:], x10)
191 xor(out[44:], in[44:], x11)
192 xor(out[48:], in[48:], x12)
193 xor(out[52:], in[52:], x13)
194 xor(out[56:], in[56:], x14)
195 xor(out[60:], in[60:], x15)
197 // copy any trailing bytes out of the buffer and into dst
200 copy(dst[fin:], s.buf[len(s.buf)-64:])
204 // Advance discards bytes in the key stream until the next 64 byte block
205 // boundary is reached and updates the counter accordingly. If the key
206 // stream is already at a block boundary no bytes will be discarded and
207 // the counter will be unchanged.
208 func (s *Cipher) Advance() {
211 s.buf = [len(s.buf)]byte{}
215 // XORKeyStream crypts bytes from in to out using the given key and counters.
216 // In and out must overlap entirely or not at all. Counter contains the raw
217 // ChaCha20 counter bytes (i.e. block counter followed by nonce).
218 func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
221 binary.LittleEndian.Uint32(key[0:4]),
222 binary.LittleEndian.Uint32(key[4:8]),
223 binary.LittleEndian.Uint32(key[8:12]),
224 binary.LittleEndian.Uint32(key[12:16]),
225 binary.LittleEndian.Uint32(key[16:20]),
226 binary.LittleEndian.Uint32(key[20:24]),
227 binary.LittleEndian.Uint32(key[24:28]),
228 binary.LittleEndian.Uint32(key[28:32]),
231 binary.LittleEndian.Uint32(counter[4:8]),
232 binary.LittleEndian.Uint32(counter[8:12]),
233 binary.LittleEndian.Uint32(counter[12:16]),
235 counter: binary.LittleEndian.Uint32(counter[0:4]),
237 s.XORKeyStream(out, in)
240 // HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
241 // nonce. It should only be used as part of the XChaCha20 construction.
242 func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
243 x0, x1, x2, x3 := j0, j1, j2, j3
244 x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
245 x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
246 x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
248 for i := 0; i < 10; i++ {
249 x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
250 x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
251 x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
252 x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
254 x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
255 x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
256 x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
257 x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
261 out[0], out[1], out[2], out[3] = x0, x1, x2, x3
262 out[4], out[5], out[6], out[7] = x12, x13, x14, x15