...

Source file src/pkg/vendor/golang.org/x/crypto/internal/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 core ChaCha20 function as specified
     6	// in https://tools.ietf.org/html/rfc7539#section-2.3.
     7	package chacha20
     8	
     9	import (
    10		"crypto/cipher"
    11		"encoding/binary"
    12	
    13		"golang.org/x/crypto/internal/subtle"
    14	)
    15	
    16	// assert that *Cipher implements cipher.Stream
    17	var _ cipher.Stream = (*Cipher)(nil)
    18	
    19	// Cipher is a stateful instance of ChaCha20 using a particular key
    20	// and nonce. A *Cipher implements the cipher.Stream interface.
    21	type Cipher struct {
    22		key     [8]uint32
    23		counter uint32 // incremented after each block
    24		nonce   [3]uint32
    25		buf     [bufSize]byte // buffer for unused keystream bytes
    26		len     int           // number of unused keystream bytes at end of buf
    27	}
    28	
    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}
    33	}
    34	
    35	// ChaCha20 constants spelling "expand 32-byte k"
    36	const (
    37		j0 uint32 = 0x61707865
    38		j1 uint32 = 0x3320646e
    39		j2 uint32 = 0x79622d32
    40		j3 uint32 = 0x6b206574
    41	)
    42	
    43	func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
    44		a += b
    45		d ^= a
    46		d = (d << 16) | (d >> 16)
    47		c += d
    48		b ^= c
    49		b = (b << 12) | (b >> 20)
    50		a += b
    51		d ^= a
    52		d = (d << 8) | (d >> 24)
    53		c += d
    54		b ^= c
    55		b = (b << 7) | (b >> 25)
    56		return a, b, c, d
    57	}
    58	
    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.
    61	//
    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.
    65	//
    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")
    72		}
    73		if subtle.InexactOverlap(dst[:len(src)], src) {
    74			panic("chacha20: invalid buffer overlap")
    75		}
    76	
    77		// xor src with buffered keystream first
    78		if s.len != 0 {
    79			buf := s.buf[len(s.buf)-s.len:]
    80			if len(src) < len(buf) {
    81				buf = buf[:len(src)]
    82			}
    83			td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
    84			for i, b := range buf {
    85				td[i] = ts[i] ^ b
    86			}
    87			s.len -= len(buf)
    88			if s.len != 0 {
    89				return
    90			}
    91			s.buf = [len(s.buf)]byte{} // zero the empty buffer
    92			src = src[len(buf):]
    93			dst = dst[len(buf):]
    94		}
    95	
    96		if len(src) == 0 {
    97			return
    98		}
    99		if haveAsm {
   100			if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
   101				panic("chacha20: counter overflow")
   102			}
   103			s.xorKeyStreamAsm(dst, src)
   104			return
   105		}
   106	
   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
   111		if rem > 0 {
   112			copy(s.buf[len(s.buf)-64:], src[fin:])
   113		}
   114	
   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])
   119	
   120		n := len(src)
   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)
   125	
   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)
   131	
   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)
   138	
   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)
   143			}
   144	
   145			x0 += j0
   146			x1 += j1
   147			x2 += j2
   148			x3 += j3
   149	
   150			x4 += s.key[0]
   151			x5 += s.key[1]
   152			x6 += s.key[2]
   153			x7 += s.key[3]
   154			x8 += s.key[4]
   155			x9 += s.key[5]
   156			x10 += s.key[6]
   157			x11 += s.key[7]
   158	
   159			x12 += s.counter
   160			x13 += s.nonce[0]
   161			x14 += s.nonce[1]
   162			x15 += s.nonce[2]
   163	
   164			// increment the counter
   165			s.counter += 1
   166			if s.counter == 0 {
   167				panic("chacha20: counter overflow")
   168			}
   169	
   170			// pad to 64 bytes if needed
   171			in, out := src[i:], dst[i:]
   172			if i == fin {
   173				// src[fin:] has already been copied into s.buf before
   174				// the main loop
   175				in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
   176			}
   177			in, out = in[:64], out[:64] // BCE hint
   178	
   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)
   196		}
   197		// copy any trailing bytes out of the buffer and into dst
   198		if rem != 0 {
   199			s.len = 64 - rem
   200			copy(dst[fin:], s.buf[len(s.buf)-64:])
   201		}
   202	}
   203	
   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() {
   209		s.len -= s.len % 64
   210		if s.len == 0 {
   211			s.buf = [len(s.buf)]byte{}
   212		}
   213	}
   214	
   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) {
   219		s := Cipher{
   220			key: [8]uint32{
   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]),
   229			},
   230			nonce: [3]uint32{
   231				binary.LittleEndian.Uint32(counter[4:8]),
   232				binary.LittleEndian.Uint32(counter[8:12]),
   233				binary.LittleEndian.Uint32(counter[12:16]),
   234			},
   235			counter: binary.LittleEndian.Uint32(counter[0:4]),
   236		}
   237		s.XORKeyStream(out, in)
   238	}
   239	
   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]
   247	
   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)
   253	
   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)
   258		}
   259	
   260		var out [8]uint32
   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
   263		return out
   264	}
   265	

View as plain text