Home | History | Annotate | Download | only in chacha20
      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 in https://tools.ietf.org/html/rfc7539#section-2.3.
      6 package chacha20
      7 
      8 import "encoding/binary"
      9 
     10 const rounds = 20
     11 
     12 // core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
     13 // and 16-byte constant c, and puts the result into 64-byte array out.
     14 func core(out *[64]byte, in *[16]byte, k *[32]byte) {
     15 	j0 := uint32(0x61707865)
     16 	j1 := uint32(0x3320646e)
     17 	j2 := uint32(0x79622d32)
     18 	j3 := uint32(0x6b206574)
     19 	j4 := binary.LittleEndian.Uint32(k[0:4])
     20 	j5 := binary.LittleEndian.Uint32(k[4:8])
     21 	j6 := binary.LittleEndian.Uint32(k[8:12])
     22 	j7 := binary.LittleEndian.Uint32(k[12:16])
     23 	j8 := binary.LittleEndian.Uint32(k[16:20])
     24 	j9 := binary.LittleEndian.Uint32(k[20:24])
     25 	j10 := binary.LittleEndian.Uint32(k[24:28])
     26 	j11 := binary.LittleEndian.Uint32(k[28:32])
     27 	j12 := binary.LittleEndian.Uint32(in[0:4])
     28 	j13 := binary.LittleEndian.Uint32(in[4:8])
     29 	j14 := binary.LittleEndian.Uint32(in[8:12])
     30 	j15 := binary.LittleEndian.Uint32(in[12:16])
     31 
     32 	x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
     33 	x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
     34 
     35 	for i := 0; i < rounds; i += 2 {
     36 		x0 += x4
     37 		x12 ^= x0
     38 		x12 = (x12 << 16) | (x12 >> (16))
     39 		x8 += x12
     40 		x4 ^= x8
     41 		x4 = (x4 << 12) | (x4 >> (20))
     42 		x0 += x4
     43 		x12 ^= x0
     44 		x12 = (x12 << 8) | (x12 >> (24))
     45 		x8 += x12
     46 		x4 ^= x8
     47 		x4 = (x4 << 7) | (x4 >> (25))
     48 		x1 += x5
     49 		x13 ^= x1
     50 		x13 = (x13 << 16) | (x13 >> 16)
     51 		x9 += x13
     52 		x5 ^= x9
     53 		x5 = (x5 << 12) | (x5 >> 20)
     54 		x1 += x5
     55 		x13 ^= x1
     56 		x13 = (x13 << 8) | (x13 >> 24)
     57 		x9 += x13
     58 		x5 ^= x9
     59 		x5 = (x5 << 7) | (x5 >> 25)
     60 		x2 += x6
     61 		x14 ^= x2
     62 		x14 = (x14 << 16) | (x14 >> 16)
     63 		x10 += x14
     64 		x6 ^= x10
     65 		x6 = (x6 << 12) | (x6 >> 20)
     66 		x2 += x6
     67 		x14 ^= x2
     68 		x14 = (x14 << 8) | (x14 >> 24)
     69 		x10 += x14
     70 		x6 ^= x10
     71 		x6 = (x6 << 7) | (x6 >> 25)
     72 		x3 += x7
     73 		x15 ^= x3
     74 		x15 = (x15 << 16) | (x15 >> 16)
     75 		x11 += x15
     76 		x7 ^= x11
     77 		x7 = (x7 << 12) | (x7 >> 20)
     78 		x3 += x7
     79 		x15 ^= x3
     80 		x15 = (x15 << 8) | (x15 >> 24)
     81 		x11 += x15
     82 		x7 ^= x11
     83 		x7 = (x7 << 7) | (x7 >> 25)
     84 		x0 += x5
     85 		x15 ^= x0
     86 		x15 = (x15 << 16) | (x15 >> 16)
     87 		x10 += x15
     88 		x5 ^= x10
     89 		x5 = (x5 << 12) | (x5 >> 20)
     90 		x0 += x5
     91 		x15 ^= x0
     92 		x15 = (x15 << 8) | (x15 >> 24)
     93 		x10 += x15
     94 		x5 ^= x10
     95 		x5 = (x5 << 7) | (x5 >> 25)
     96 		x1 += x6
     97 		x12 ^= x1
     98 		x12 = (x12 << 16) | (x12 >> 16)
     99 		x11 += x12
    100 		x6 ^= x11
    101 		x6 = (x6 << 12) | (x6 >> 20)
    102 		x1 += x6
    103 		x12 ^= x1
    104 		x12 = (x12 << 8) | (x12 >> 24)
    105 		x11 += x12
    106 		x6 ^= x11
    107 		x6 = (x6 << 7) | (x6 >> 25)
    108 		x2 += x7
    109 		x13 ^= x2
    110 		x13 = (x13 << 16) | (x13 >> 16)
    111 		x8 += x13
    112 		x7 ^= x8
    113 		x7 = (x7 << 12) | (x7 >> 20)
    114 		x2 += x7
    115 		x13 ^= x2
    116 		x13 = (x13 << 8) | (x13 >> 24)
    117 		x8 += x13
    118 		x7 ^= x8
    119 		x7 = (x7 << 7) | (x7 >> 25)
    120 		x3 += x4
    121 		x14 ^= x3
    122 		x14 = (x14 << 16) | (x14 >> 16)
    123 		x9 += x14
    124 		x4 ^= x9
    125 		x4 = (x4 << 12) | (x4 >> 20)
    126 		x3 += x4
    127 		x14 ^= x3
    128 		x14 = (x14 << 8) | (x14 >> 24)
    129 		x9 += x14
    130 		x4 ^= x9
    131 		x4 = (x4 << 7) | (x4 >> 25)
    132 	}
    133 
    134 	x0 += j0
    135 	x1 += j1
    136 	x2 += j2
    137 	x3 += j3
    138 	x4 += j4
    139 	x5 += j5
    140 	x6 += j6
    141 	x7 += j7
    142 	x8 += j8
    143 	x9 += j9
    144 	x10 += j10
    145 	x11 += j11
    146 	x12 += j12
    147 	x13 += j13
    148 	x14 += j14
    149 	x15 += j15
    150 
    151 	binary.LittleEndian.PutUint32(out[0:4], x0)
    152 	binary.LittleEndian.PutUint32(out[4:8], x1)
    153 	binary.LittleEndian.PutUint32(out[8:12], x2)
    154 	binary.LittleEndian.PutUint32(out[12:16], x3)
    155 	binary.LittleEndian.PutUint32(out[16:20], x4)
    156 	binary.LittleEndian.PutUint32(out[20:24], x5)
    157 	binary.LittleEndian.PutUint32(out[24:28], x6)
    158 	binary.LittleEndian.PutUint32(out[28:32], x7)
    159 	binary.LittleEndian.PutUint32(out[32:36], x8)
    160 	binary.LittleEndian.PutUint32(out[36:40], x9)
    161 	binary.LittleEndian.PutUint32(out[40:44], x10)
    162 	binary.LittleEndian.PutUint32(out[44:48], x11)
    163 	binary.LittleEndian.PutUint32(out[48:52], x12)
    164 	binary.LittleEndian.PutUint32(out[52:56], x13)
    165 	binary.LittleEndian.PutUint32(out[56:60], x14)
    166 	binary.LittleEndian.PutUint32(out[60:64], x15)
    167 }
    168 
    169 // XORKeyStream crypts bytes from in to out using the given key and counters.
    170 // In and out may be the same slice but otherwise should not overlap. Counter
    171 // contains the raw ChaCha20 counter bytes (i.e. block counter followed by
    172 // nonce).
    173 func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
    174 	var block [64]byte
    175 	var counterCopy [16]byte
    176 	copy(counterCopy[:], counter[:])
    177 
    178 	for len(in) >= 64 {
    179 		core(&block, &counterCopy, key)
    180 		for i, x := range block {
    181 			out[i] = in[i] ^ x
    182 		}
    183 		u := uint32(1)
    184 		for i := 0; i < 4; i++ {
    185 			u += uint32(counterCopy[i])
    186 			counterCopy[i] = byte(u)
    187 			u >>= 8
    188 		}
    189 		in = in[64:]
    190 		out = out[64:]
    191 	}
    192 
    193 	if len(in) > 0 {
    194 		core(&block, &counterCopy, key)
    195 		for i, v := range in {
    196 			out[i] = v ^ block[i]
    197 		}
    198 	}
    199 }
    200