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