chacha20.go raw

   1  package chacha20
   2  
   3  // XOR encrypts/decrypts data using ChaCha20.
   4  // key: 32 bytes, nonce: 12 bytes.
   5  func XOR(key [32]byte, nonce [12]byte, data []byte) []byte {
   6  	out := make([]byte, len(data))
   7  	var state [16]uint32
   8  	// "expand 32-byte k"
   9  	state[0] = 0x61707865
  10  	state[1] = 0x3320646e
  11  	state[2] = 0x79622d32
  12  	state[3] = 0x6b206574
  13  	state[4] = le32(key[0:4])
  14  	state[5] = le32(key[4:8])
  15  	state[6] = le32(key[8:12])
  16  	state[7] = le32(key[12:16])
  17  	state[8] = le32(key[16:20])
  18  	state[9] = le32(key[20:24])
  19  	state[10] = le32(key[24:28])
  20  	state[11] = le32(key[28:32])
  21  	// counter = 0
  22  	state[12] = 0
  23  	state[13] = le32(nonce[0:4])
  24  	state[14] = le32(nonce[4:8])
  25  	state[15] = le32(nonce[8:12])
  26  
  27  	pos := 0
  28  	for pos < len(data) {
  29  		var block [64]byte
  30  		blockFn(&state, &block)
  31  		state[12]++ // increment counter
  32  		n := min(len(data)-pos, 64)
  33  		for i := range n {
  34  			out[pos+i] = data[pos+i] ^ block[i]
  35  		}
  36  		pos += n
  37  	}
  38  	return out
  39  }
  40  
  41  func blockFn(state *[16]uint32, out *[64]byte) {
  42  	var s [16]uint32
  43  	copy(s[:], state[:])
  44  
  45  	for range 10 {
  46  		// column rounds
  47  		qr(&s, 0, 4, 8, 12)
  48  		qr(&s, 1, 5, 9, 13)
  49  		qr(&s, 2, 6, 10, 14)
  50  		qr(&s, 3, 7, 11, 15)
  51  		// diagonal rounds
  52  		qr(&s, 0, 5, 10, 15)
  53  		qr(&s, 1, 6, 11, 12)
  54  		qr(&s, 2, 7, 8, 13)
  55  		qr(&s, 3, 4, 9, 14)
  56  	}
  57  
  58  	for i := range 16 {
  59  		v := s[i] + state[i]
  60  		out[i*4] = byte(v)
  61  		out[i*4+1] = byte(v >> 8)
  62  		out[i*4+2] = byte(v >> 16)
  63  		out[i*4+3] = byte(v >> 24)
  64  	}
  65  }
  66  
  67  func qr(s *[16]uint32, a, b, c, d int) {
  68  	s[a] += s[b]
  69  	s[d] ^= s[a]
  70  	s[d] = (s[d] << 16) | (s[d] >> 16)
  71  	s[c] += s[d]
  72  	s[b] ^= s[c]
  73  	s[b] = (s[b] << 12) | (s[b] >> 20)
  74  	s[a] += s[b]
  75  	s[d] ^= s[a]
  76  	s[d] = (s[d] << 8) | (s[d] >> 24)
  77  	s[c] += s[d]
  78  	s[b] ^= s[c]
  79  	s[b] = (s[b] << 7) | (s[b] >> 25)
  80  }
  81  
  82  func le32(b []byte) uint32 {
  83  	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
  84  }
  85