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