Source file src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go

     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  }
   399  

View as plain text