Added CCM and CCM_8 cipher suites.
[BoarSSL] / Crypto / ChaCha20.cs
1 /*
2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3 *
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:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
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
22 * SOFTWARE.
23 */
24
25 using System;
26
27 namespace Crypto {
28
29 /*
30 * ChaCha20 implementation.
31 */
32
33 public sealed class ChaCha20 {
34
35 uint k0, k1, k2, k3, k4, k5, k6, k7;
36
37 const uint CW0 = 0x61707865;
38 const uint CW1 = 0x3320646E;
39 const uint CW2 = 0x79622D32;
40 const uint CW3 = 0x6B206574;
41
42 /*
43 * Initialize a new instance.
44 */
45 public ChaCha20()
46 {
47 }
48
49 /*
50 * Set the key (32 bytes).
51 */
52 public void SetKey(byte[] key)
53 {
54 SetKey(key, 0, key.Length);
55 }
56
57 /*
58 * Set the key (32 bytes).
59 */
60 public void SetKey(byte[] key, int off, int len)
61 {
62 if (len != 32) {
63 throw new ArgumentException(
64 "bad ChaCha20 key length: " + len);
65 }
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);
74 }
75
76 /*
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.
84 *
85 * IV must be exactly 12 bytes.
86 */
87 public uint Run(byte[] iv, uint cc, byte[] data)
88 {
89 return Run(iv, cc, data, 0, data.Length);
90 }
91
92 /*
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.
100 *
101 * IV must be exactly 12 bytes.
102 */
103 public uint Run(byte[] iv, uint cc, byte[] data, int off, int len)
104 {
105 uint iv0 = Dec32le(iv, 0);
106 uint iv1 = Dec32le(iv, 4);
107 uint iv2 = Dec32le(iv, 8);
108 while (len > 0) {
109 uint s0, s1, s2, s3, s4, s5, s6, s7;
110 uint s8, s9, sA, sB, sC, sD, sE, sF;
111
112 s0 = CW0;
113 s1 = CW1;
114 s2 = CW2;
115 s3 = CW3;
116 s4 = k0;
117 s5 = k1;
118 s6 = k2;
119 s7 = k3;
120 s8 = k4;
121 s9 = k5;
122 sA = k6;
123 sB = k7;
124 sC = cc;
125 sD = iv0;
126 sE = iv1;
127 sF = iv2;
128
129 for (int i = 0; i < 10; i ++) {
130 s0 += s4;
131 sC ^= s0;
132 sC = (sC << 16) | (sC >> 16);
133 s8 += sC;
134 s4 ^= s8;
135 s4 = (s4 << 12) | (s4 >> 20);
136 s0 += s4;
137 sC ^= s0;
138 sC = (sC << 8) | (sC >> 24);
139 s8 += sC;
140 s4 ^= s8;
141 s4 = (s4 << 7) | (s4 >> 25);
142
143 s1 += s5;
144 sD ^= s1;
145 sD = (sD << 16) | (sD >> 16);
146 s9 += sD;
147 s5 ^= s9;
148 s5 = (s5 << 12) | (s5 >> 20);
149 s1 += s5;
150 sD ^= s1;
151 sD = (sD << 8) | (sD >> 24);
152 s9 += sD;
153 s5 ^= s9;
154 s5 = (s5 << 7) | (s5 >> 25);
155
156 s2 += s6;
157 sE ^= s2;
158 sE = (sE << 16) | (sE >> 16);
159 sA += sE;
160 s6 ^= sA;
161 s6 = (s6 << 12) | (s6 >> 20);
162 s2 += s6;
163 sE ^= s2;
164 sE = (sE << 8) | (sE >> 24);
165 sA += sE;
166 s6 ^= sA;
167 s6 = (s6 << 7) | (s6 >> 25);
168
169 s3 += s7;
170 sF ^= s3;
171 sF = (sF << 16) | (sF >> 16);
172 sB += sF;
173 s7 ^= sB;
174 s7 = (s7 << 12) | (s7 >> 20);
175 s3 += s7;
176 sF ^= s3;
177 sF = (sF << 8) | (sF >> 24);
178 sB += sF;
179 s7 ^= sB;
180 s7 = (s7 << 7) | (s7 >> 25);
181
182 s0 += s5;
183 sF ^= s0;
184 sF = (sF << 16) | (sF >> 16);
185 sA += sF;
186 s5 ^= sA;
187 s5 = (s5 << 12) | (s5 >> 20);
188 s0 += s5;
189 sF ^= s0;
190 sF = (sF << 8) | (sF >> 24);
191 sA += sF;
192 s5 ^= sA;
193 s5 = (s5 << 7) | (s5 >> 25);
194
195 s1 += s6;
196 sC ^= s1;
197 sC = (sC << 16) | (sC >> 16);
198 sB += sC;
199 s6 ^= sB;
200 s6 = (s6 << 12) | (s6 >> 20);
201 s1 += s6;
202 sC ^= s1;
203 sC = (sC << 8) | (sC >> 24);
204 sB += sC;
205 s6 ^= sB;
206 s6 = (s6 << 7) | (s6 >> 25);
207
208 s2 += s7;
209 sD ^= s2;
210 sD = (sD << 16) | (sD >> 16);
211 s8 += sD;
212 s7 ^= s8;
213 s7 = (s7 << 12) | (s7 >> 20);
214 s2 += s7;
215 sD ^= s2;
216 sD = (sD << 8) | (sD >> 24);
217 s8 += sD;
218 s7 ^= s8;
219 s7 = (s7 << 7) | (s7 >> 25);
220
221 s3 += s4;
222 sE ^= s3;
223 sE = (sE << 16) | (sE >> 16);
224 s9 += sE;
225 s4 ^= s9;
226 s4 = (s4 << 12) | (s4 >> 20);
227 s3 += s4;
228 sE ^= s3;
229 sE = (sE << 8) | (sE >> 24);
230 s9 += sE;
231 s4 ^= s9;
232 s4 = (s4 << 7) | (s4 >> 25);
233 }
234
235 s0 += CW0;
236 s1 += CW1;
237 s2 += CW2;
238 s3 += CW3;
239 s4 += k0;
240 s5 += k1;
241 s6 += k2;
242 s7 += k3;
243 s8 += k4;
244 s9 += k5;
245 sA += k6;
246 sB += k7;
247 sC += cc;
248 sD += iv0;
249 sE += iv1;
250 sF += iv2;
251
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);
269
270 off += 64;
271 len -= 64;
272 cc ++;
273 }
274 return cc;
275 }
276
277 static uint Dec32le(byte[] buf, int off)
278 {
279 return (uint)buf[off]
280 | ((uint)buf[off + 1] << 8)
281 | ((uint)buf[off + 2] << 16)
282 | ((uint)buf[off + 3] << 24);
283 }
284
285 static void Xor32le(uint x, byte[] buf, int off, int limit)
286 {
287 if (off + 4 <= limit) {
288 buf[off] ^= (byte)x;
289 buf[off + 1] ^= (byte)(x >> 8);
290 buf[off + 2] ^= (byte)(x >> 16);
291 buf[off + 3] ^= (byte)(x >> 24);
292 } else {
293 if (off + 2 <= limit) {
294 if (off + 3 <= limit) {
295 buf[off] ^= (byte)x;
296 buf[off + 1] ^= (byte)(x >> 8);
297 buf[off + 2] ^= (byte)(x >> 16);
298 } else {
299 buf[off] ^= (byte)x;
300 buf[off + 1] ^= (byte)(x >> 8);
301 }
302 } else {
303 if (off + 1 <= limit) {
304 buf[off] ^= (byte)x;
305 }
306 }
307 }
308 }
309 }
310
311 }