2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * ChaCha20 implementation.
33 public sealed class ChaCha20 {
35 uint k0, k1, k2, k3, k4, k5, k6, k7;
37 const uint CW0 = 0x61707865;
38 const uint CW1 = 0x3320646E;
39 const uint CW2 = 0x79622D32;
40 const uint CW3 = 0x6B206574;
43 * Initialize a new instance.
50 * Set the key (32 bytes).
52 public void SetKey(byte[] key)
54 SetKey(key, 0, key.Length);
58 * Set the key (32 bytes).
60 public void SetKey(byte[] key, int off, int len)
63 throw new ArgumentException(
64 "bad ChaCha20 key length: " + len);
66 k0 = Dec32le(key, off + 0);
67 k1 = Dec32le(key, off + 4);
68 k2 = Dec32le(key, off + 8);
69 k3 = Dec32le(key, off + 12);
70 k4 = Dec32le(key, off + 16);
71 k5 = Dec32le(key, off + 20);
72 k6 = Dec32le(key, off + 24);
73 k7 = Dec32le(key, off + 28);
77 * Encrypt (or decrypt) some bytes. The current block counter
78 * is provided, and the new block counter value is returned.
79 * Each block is 64 bytes; if the data length is not a multiple
80 * of 64, then the extra bytes from the last block are dropped;
81 * thus, a long stream of bytes can be encrypted or decrypted
82 * in several calls, as long as all calls (except possibly the
83 * last) provide a length that is a multiple of 64.
85 * IV must be exactly 12 bytes.
87 public uint Run(byte[] iv, uint cc, byte[] data)
89 return Run(iv, cc, data, 0, data.Length);
93 * Encrypt (or decrypt) some bytes. The current block counter
94 * is provided, and the new block counter value is returned.
95 * Each block is 64 bytes; if the data length is not a multiple
96 * of 64, then the extra bytes from the last block are dropped;
97 * thus, a long stream of bytes can be encrypted or decrypted
98 * in several calls, as long as all calls (except possibly the
99 * last) provide a length that is a multiple of 64.
101 * IV must be exactly 12 bytes.
103 public uint Run(byte[] iv, uint cc, byte[] data, int off, int len)
105 uint iv0 = Dec32le(iv, 0);
106 uint iv1 = Dec32le(iv, 4);
107 uint iv2 = Dec32le(iv, 8);
109 uint s0, s1, s2, s3, s4, s5, s6, s7;
110 uint s8, s9, sA, sB, sC, sD, sE, sF;
129 for (int i = 0; i < 10; i ++) {
132 sC = (sC << 16) | (sC >> 16);
135 s4 = (s4 << 12) | (s4 >> 20);
138 sC = (sC << 8) | (sC >> 24);
141 s4 = (s4 << 7) | (s4 >> 25);
145 sD = (sD << 16) | (sD >> 16);
148 s5 = (s5 << 12) | (s5 >> 20);
151 sD = (sD << 8) | (sD >> 24);
154 s5 = (s5 << 7) | (s5 >> 25);
158 sE = (sE << 16) | (sE >> 16);
161 s6 = (s6 << 12) | (s6 >> 20);
164 sE = (sE << 8) | (sE >> 24);
167 s6 = (s6 << 7) | (s6 >> 25);
171 sF = (sF << 16) | (sF >> 16);
174 s7 = (s7 << 12) | (s7 >> 20);
177 sF = (sF << 8) | (sF >> 24);
180 s7 = (s7 << 7) | (s7 >> 25);
184 sF = (sF << 16) | (sF >> 16);
187 s5 = (s5 << 12) | (s5 >> 20);
190 sF = (sF << 8) | (sF >> 24);
193 s5 = (s5 << 7) | (s5 >> 25);
197 sC = (sC << 16) | (sC >> 16);
200 s6 = (s6 << 12) | (s6 >> 20);
203 sC = (sC << 8) | (sC >> 24);
206 s6 = (s6 << 7) | (s6 >> 25);
210 sD = (sD << 16) | (sD >> 16);
213 s7 = (s7 << 12) | (s7 >> 20);
216 sD = (sD << 8) | (sD >> 24);
219 s7 = (s7 << 7) | (s7 >> 25);
223 sE = (sE << 16) | (sE >> 16);
226 s4 = (s4 << 12) | (s4 >> 20);
229 sE = (sE << 8) | (sE >> 24);
232 s4 = (s4 << 7) | (s4 >> 25);
252 int limit = off + len;
253 Xor32le(s0, data, off + 0, limit);
254 Xor32le(s1, data, off + 4, limit);
255 Xor32le(s2, data, off + 8, limit);
256 Xor32le(s3, data, off + 12, limit);
257 Xor32le(s4, data, off + 16, limit);
258 Xor32le(s5, data, off + 20, limit);
259 Xor32le(s6, data, off + 24, limit);
260 Xor32le(s7, data, off + 28, limit);
261 Xor32le(s8, data, off + 32, limit);
262 Xor32le(s9, data, off + 36, limit);
263 Xor32le(sA, data, off + 40, limit);
264 Xor32le(sB, data, off + 44, limit);
265 Xor32le(sC, data, off + 48, limit);
266 Xor32le(sD, data, off + 52, limit);
267 Xor32le(sE, data, off + 56, limit);
268 Xor32le(sF, data, off + 60, limit);
277 static uint Dec32le(byte[] buf, int off)
279 return (uint)buf[off]
280 | ((uint)buf[off + 1] << 8)
281 | ((uint)buf[off + 2] << 16)
282 | ((uint)buf[off + 3] << 24);
285 static void Xor32le(uint x, byte[] buf, int off, int limit)
287 if (off + 4 <= limit) {
289 buf[off + 1] ^= (byte)(x >> 8);
290 buf[off + 2] ^= (byte)(x >> 16);
291 buf[off + 3] ^= (byte)(x >> 24);
293 if (off + 2 <= limit) {
294 if (off + 3 <= limit) {
296 buf[off + 1] ^= (byte)(x >> 8);
297 buf[off + 2] ^= (byte)(x >> 16);
300 buf[off + 1] ^= (byte)(x >> 8);
303 if (off + 1 <= limit) {