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 * This class implements Poly1305, when used with ChaCha20. The
31 * ChaCha20 instance (already set with the secret key) is passed as
32 * parameter. Instances are not thread-safe.
35 public sealed class Poly1305 {
38 * The ChaCha20 instance to use for encryption and decryption.
39 * That instance MUST be set, and it must have been initialised
40 * with the key to use.
42 public ChaCha20 ChaCha {
53 * Create a new instance. The ChaCha20 instance to use MUST be
54 * set in the 'ChaCha' property.
66 * Run Poly1305 and ChaCha20 on the provided elements.
68 * iv Nonce for ChaCha20, exactly 12 bytes
69 * data data to encrypt or decrypt (buffer, off + len)
70 * aad additional authenticated data (buffer, offAAD + lenAAD)
71 * tag destination for computed authentication tag
72 * encrypt true to encrypt, false to decrypt
74 public void Run(byte[] iv,
75 byte[] data, int off, int len,
76 byte[] aad, int offAAD, int lenAAD,
77 byte[] tag, bool encrypt)
80 * Compute Poly1305 key.
82 for (int i = 0; i < pkey.Length; i ++) {
85 ChaCha.Run(iv, 0, pkey);
88 * If encrypting, ChaCha20 must run first (the MAC is
89 * computed on the ciphertext).
92 ChaCha.Run(iv, 1, data, off, len);
96 * Decode the 'r' value into 26-bit words, with the
97 * "clamping" operation applied.
99 r[0] = Dec32le(pkey, 0) & 0x03FFFFFF;
100 r[1] = (Dec32le(pkey, 3) >> 2) & 0x03FFFF03;
101 r[2] = (Dec32le(pkey, 6) >> 4) & 0x03FFC0FF;
102 r[3] = (Dec32le(pkey, 9) >> 6) & 0x03F03FFF;
103 r[4] = (Dec32le(pkey, 12) >> 8) & 0x000FFFFF;
115 * Process AAD, ciphertext and footer.
117 Enc32le(lenAAD, foot, 0);
119 Enc32le(len, foot, 8);
120 Enc32le(0, foot, 12);
121 RunInner(aad, offAAD, lenAAD);
122 RunInner(data, off, len);
123 RunInner(foot, 0, 16);
126 * Finalize modular reduction. The output of RunInner() is
127 * already mostly reduced: only acc[1] may be (very slightly)
128 * above 2^26. Thus, we only need one loop, back to acc[1].
131 for (int i = 1; i <= 6; i ++) {
134 j = (i >= 5) ? i - 5 : i;
137 acc[j] &= 0x03FFFFFF;
141 * The final value may still be in the 2^130-5..2^130-1
142 * range, in which case an additional subtraction must be
143 * performed, with constant-time code.
145 cc = (uint)((int)(0x03FFFFFA - acc[0]) >> 31);
146 for (int i = 1; i < 5; i ++) {
147 int z = (int)(acc[i] - 0x03FFFFFF);
148 cc &= ~(uint)((z | -z) >> 31);
151 for (int i = 0; i < 5; i ++) {
152 uint t = acc[i] + cc;
154 acc[i] = t & 0x03FFFFFF;
158 * The tag is the sum of the 's' value (second half of
159 * the pkey[] array, little-endian encoding) and the
160 * current accumulator value. This addition is done modulo
161 * 2^128, i.e. with a simple truncation.
166 for (int i = 0, j = 0; i < 16; i ++) {
169 * We "refill" our running byte buffer with
170 * a new extra accumulator word. Note that
171 * 'awLen' is always even, so at this point
172 * it must be 6 or less; since accumulator
173 * words fit on 32 bits, the operation
174 * below does not lose any bit.
176 aw |= acc[j ++] << awLen;
179 uint tb = (aw & 0xFF) + cc + pkey[16 + i];
187 * If decrypting, then we still have the ciphertext at
188 * this point, and we must perform the decryption.
191 ChaCha.Run(iv, 1, data, off, len);
196 * Inner processing of the provided data. The accumulator and 'r'
197 * value are set in the instance fields, and must be updated.
198 * All accumulator words fit on 26 bits each, except the second
199 * (acc[1]) which may be very slightly above 2^26.
201 void RunInner(byte[] data, int off, int len)
204 * Implementation is inspired from the public-domain code
206 * https://github.com/floodyberry/poly1305-donna
227 Array.Copy(data, off, tmp, 0, len);
228 for (int i = len; i < 16; i ++) {
236 * Decode next block, with the "high bit" applied,
237 * and add that value to the accumulator.
239 a0 += Dec32le(data, off) & 0x03FFFFFF;
240 a1 += (Dec32le(data, off + 3) >> 2) & 0x03FFFFFF;
241 a2 += (Dec32le(data, off + 6) >> 4) & 0x03FFFFFF;
242 a3 += (Dec32le(data, off + 9) >> 6) & 0x03FFFFFF;
243 a4 += (Dec32le(data, off + 12) >> 8) | 0x01000000;
246 * Compute multiplication. All elementary
247 * multiplications are 32x32->64.
249 ulong w0 = (ulong)a0 * r0
254 ulong w1 = (ulong)a0 * r1
259 ulong w2 = (ulong)a0 * r2
264 ulong w3 = (ulong)a0 * r3
269 ulong w4 = (ulong)a0 * r4
276 * Most of the modular reduction was done by using
277 * the 'u*' multipliers. We still need to do some
282 a0 = (uint)w0 & 0x03FFFFFF;
285 a1 = (uint)w1 & 0x03FFFFFF;
288 a2 = (uint)w2 & 0x03FFFFFF;
291 a3 = (uint)w3 & 0x03FFFFFF;
294 a4 = (uint)w4 & 0x03FFFFFF;
310 static uint Dec32le(byte[] buf, int off)
312 return (uint)buf[off]
313 | ((uint)buf[off + 1] << 8)
314 | ((uint)buf[off + 2] << 16)
315 | ((uint)buf[off + 3] << 24);
318 static void Enc32le(int x, byte[] buf, int off)
321 buf[off + 1] = (byte)(x >> 8);
322 buf[off + 2] = (byte)(x >> 16);
323 buf[off + 3] = (byte)(x >> 24);