/src/cryptopp/poly1305.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // poly1305.cpp - written and placed in the public domain by Jeffrey Walton and Jean-Pierre Munch |
2 | | // Based on Andy Polyakov's Base-2^26 scalar multiplication implementation. |
3 | | // For more information, see https://www.openssl.org/~appro/cryptogams/. |
4 | | |
5 | | // Copyright (c) 2006-2017, CRYPTOGAMS by <appro@openssl.org> |
6 | | // All rights reserved. |
7 | | // |
8 | | // Redistribution and use in source and binary forms, with or without |
9 | | // modification, are permitted provided that the following conditions |
10 | | // are met: |
11 | | // |
12 | | // * Redistributions of source code must retain copyright notices, |
13 | | // this list of conditions and the following disclaimer. |
14 | | // * Redistributions in binary form must reproduce the above |
15 | | // copyright notice, this list of conditions and the following |
16 | | // disclaimer in the documentation and/or other materials |
17 | | // provided with the distribution. |
18 | | // * Neither the name of the CRYPTOGAMS nor the names of its copyright |
19 | | // holder and contributors may be used to endorse or promote products |
20 | | // derived from this software without specific prior written permission. |
21 | | |
22 | | #include "pch.h" |
23 | | #include "cryptlib.h" |
24 | | #include "poly1305.h" |
25 | | #include "aes.h" |
26 | | #include "cpu.h" |
27 | | |
28 | | ////////////////////////////// Common Poly1305 ////////////////////////////// |
29 | | |
30 | | ANONYMOUS_NAMESPACE_BEGIN |
31 | | |
32 | | using namespace CryptoPP; |
33 | | |
34 | | inline word32 CONSTANT_TIME_CARRY(word32 a, word32 b) |
35 | 388 | { |
36 | 388 | return ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1)); |
37 | 388 | } |
38 | | |
39 | | void Poly1305_HashBlocks(word32 h[5], word32 r[4], const byte *input, size_t length, word32 padbit) |
40 | 51 | { |
41 | 51 | word32 r0, r1, r2, r3; |
42 | 51 | word32 s1, s2, s3; |
43 | 51 | word32 h0, h1, h2, h3, h4, c; |
44 | 51 | word64 d0, d1, d2, d3; |
45 | | |
46 | 51 | r0 = r[0]; r1 = r[1]; |
47 | 51 | r2 = r[2]; r3 = r[3]; |
48 | | |
49 | 51 | s1 = r1 + (r1 >> 2); |
50 | 51 | s2 = r2 + (r2 >> 2); |
51 | 51 | s3 = r3 + (r3 >> 2); |
52 | | |
53 | 51 | h0 = h[0]; h1 = h[1]; h2 = h[2]; |
54 | 51 | h3 = h[3]; h4 = h[4]; |
55 | | |
56 | 148 | while (length >= 16) |
57 | 97 | { |
58 | | // h += m[i] |
59 | 97 | h0 = (word32)(d0 = (word64)h0 + GetWord<word32>(false, LITTLE_ENDIAN_ORDER, input + 0)); |
60 | 97 | h1 = (word32)(d1 = (word64)h1 + (d0 >> 32) + GetWord<word32>(false, LITTLE_ENDIAN_ORDER, input + 4)); |
61 | 97 | h2 = (word32)(d2 = (word64)h2 + (d1 >> 32) + GetWord<word32>(false, LITTLE_ENDIAN_ORDER, input + 8)); |
62 | 97 | h3 = (word32)(d3 = (word64)h3 + (d2 >> 32) + GetWord<word32>(false, LITTLE_ENDIAN_ORDER, input + 12)); |
63 | 97 | h4 += (word32)(d3 >> 32) + padbit; |
64 | | |
65 | | // h *= r "%" p |
66 | 97 | d0 = ((word64)h0 * r0) + |
67 | 97 | ((word64)h1 * s3) + |
68 | 97 | ((word64)h2 * s2) + |
69 | 97 | ((word64)h3 * s1); |
70 | 97 | d1 = ((word64)h0 * r1) + |
71 | 97 | ((word64)h1 * r0) + |
72 | 97 | ((word64)h2 * s3) + |
73 | 97 | ((word64)h3 * s2) + |
74 | 97 | (h4 * s1); |
75 | 97 | d2 = ((word64)h0 * r2) + |
76 | 97 | ((word64)h1 * r1) + |
77 | 97 | ((word64)h2 * r0) + |
78 | 97 | ((word64)h3 * s3) + |
79 | 97 | (h4 * s2); |
80 | 97 | d3 = ((word64)h0 * r3) + |
81 | 97 | ((word64)h1 * r2) + |
82 | 97 | ((word64)h2 * r1) + |
83 | 97 | ((word64)h3 * r0) + |
84 | 97 | (h4 * s3); |
85 | 97 | h4 = (h4 * r0); |
86 | | |
87 | | // a) h4:h0 = h4<<128 + d3<<96 + d2<<64 + d1<<32 + d0 |
88 | 97 | h0 = (word32)d0; |
89 | 97 | h1 = (word32)(d1 += d0 >> 32); |
90 | 97 | h2 = (word32)(d2 += d1 >> 32); |
91 | 97 | h3 = (word32)(d3 += d2 >> 32); |
92 | 97 | h4 += (word32)(d3 >> 32); |
93 | | |
94 | | // b) (h4:h0 += (h4:h0>>130) * 5) %= 2^130 |
95 | 97 | c = (h4 >> 2) + (h4 & ~3U); |
96 | 97 | h4 &= 3; |
97 | 97 | h0 += c; |
98 | 97 | h1 += (c = CONSTANT_TIME_CARRY(h0,c)); |
99 | 97 | h2 += (c = CONSTANT_TIME_CARRY(h1,c)); |
100 | 97 | h3 += (c = CONSTANT_TIME_CARRY(h2,c)); |
101 | 97 | h4 += CONSTANT_TIME_CARRY(h3,c); |
102 | | |
103 | 97 | input += 16; |
104 | 97 | length -= 16; |
105 | 97 | } |
106 | | |
107 | 51 | h[0] = h0; h[1] = h1; h[2] = h2; |
108 | 51 | h[3] = h3; h[4] = h4; |
109 | 51 | } |
110 | | |
111 | | void Poly1305_HashFinal(word32 h[5], word32 n[4], byte *mac, size_t size) |
112 | 13 | { |
113 | 13 | word32 h0, h1, h2, h3, h4; |
114 | 13 | word32 g0, g1, g2, g3, g4; |
115 | 13 | word32 mask; |
116 | 13 | word64 t; |
117 | | |
118 | 13 | h0 = h[0]; |
119 | 13 | h1 = h[1]; |
120 | 13 | h2 = h[2]; |
121 | 13 | h3 = h[3]; |
122 | 13 | h4 = h[4]; |
123 | | |
124 | | // compare to modulus by computing h + -p |
125 | 13 | g0 = (word32)(t = (word64)h0 + 5); |
126 | 13 | g1 = (word32)(t = (word64)h1 + (t >> 32)); |
127 | 13 | g2 = (word32)(t = (word64)h2 + (t >> 32)); |
128 | 13 | g3 = (word32)(t = (word64)h3 + (t >> 32)); |
129 | 13 | g4 = h4 + (word32)(t >> 32); |
130 | | |
131 | | // if there was carry into 131st bit, h3:h0 = g3:g0 |
132 | 13 | mask = 0 - (g4 >> 2); |
133 | 13 | g0 &= mask; g1 &= mask; |
134 | 13 | g2 &= mask; g3 &= mask; |
135 | 13 | mask = ~mask; |
136 | 13 | h0 = (h0 & mask) | g0; h1 = (h1 & mask) | g1; |
137 | 13 | h2 = (h2 & mask) | g2; h3 = (h3 & mask) | g3; |
138 | | |
139 | | // mac = (h + nonce) % (2^128) |
140 | 13 | h0 = (word32)(t = (word64)h0 + n[0]); |
141 | 13 | h1 = (word32)(t = (word64)h1 + (t >> 32) + n[1]); |
142 | 13 | h2 = (word32)(t = (word64)h2 + (t >> 32) + n[2]); |
143 | 13 | h3 = (word32)(t = (word64)h3 + (t >> 32) + n[3]); |
144 | | |
145 | 13 | if (size >= 16) |
146 | 8 | { |
147 | 8 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, mac + 0, h0); |
148 | 8 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, mac + 4, h1); |
149 | 8 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, mac + 8, h2); |
150 | 8 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, mac + 12, h3); |
151 | 8 | } |
152 | 5 | else |
153 | 5 | { |
154 | 5 | FixedSizeAlignedSecBlock<byte, 16> m; |
155 | 5 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, m + 0, h0); |
156 | 5 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, m + 4, h1); |
157 | 5 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, m + 8, h2); |
158 | 5 | PutWord<word32>(false, LITTLE_ENDIAN_ORDER, m + 12, h3); |
159 | 5 | std::memcpy(mac, m, size); |
160 | 5 | } |
161 | 13 | } |
162 | | |
163 | | ANONYMOUS_NAMESPACE_END |
164 | | |
165 | | NAMESPACE_BEGIN(CryptoPP) |
166 | | |
167 | | ////////////////////////////// Bernstein Poly1305 ////////////////////////////// |
168 | | |
169 | | // TODO: No longer needed. Remove at next major version bump |
170 | | template <class T> |
171 | 0 | void Poly1305_Base<T>::HashBlocks(const byte *input, size_t length, word32 padbit) { |
172 | 0 | CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(padbit); |
173 | 0 | CRYPTOPP_ASSERT(0); |
174 | 0 | } |
175 | | |
176 | | // TODO: No longer needed. Remove at next major version bump |
177 | | template <class T> |
178 | 0 | void Poly1305_Base<T>::HashFinal(byte *mac, size_t length) { |
179 | 0 | CRYPTOPP_UNUSED(mac); CRYPTOPP_UNUSED(length); |
180 | 0 | CRYPTOPP_ASSERT(0); |
181 | 0 | } |
182 | | |
183 | | template <class T> |
184 | | std::string Poly1305_Base<T>::AlgorithmProvider() const |
185 | 0 | { |
186 | 0 | return m_cipher.AlgorithmProvider(); |
187 | 0 | } |
188 | | |
189 | | template <class T> |
190 | | void Poly1305_Base<T>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) |
191 | 0 | { |
192 | 0 | CRYPTOPP_ASSERT(key && length >= 32); |
193 | | |
194 | | // key is {k,r} pair. k is AES key, r is the additional key that gets clamped |
195 | 0 | length = SaturatingSubtract(length, (unsigned)BLOCKSIZE); |
196 | 0 | m_cipher.SetKey(key, length); |
197 | 0 | key += length; |
198 | | |
199 | | // Rbar is clamped and little endian |
200 | 0 | m_r[0] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 0) & 0x0fffffff; |
201 | 0 | m_r[1] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 4) & 0x0ffffffc; |
202 | 0 | m_r[2] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 8) & 0x0ffffffc; |
203 | 0 | m_r[3] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 12) & 0x0ffffffc; |
204 | | |
205 | | // Mark the nonce as dirty, meaning we need a new one |
206 | 0 | m_used = true; |
207 | |
|
208 | 0 | ConstByteArrayParameter t; |
209 | 0 | if (params.GetValue(Name::IV(), t) && t.begin() && t.size()) |
210 | 0 | { |
211 | 0 | CRYPTOPP_ASSERT(t.size() == m_nk.size()); |
212 | 0 | Resynchronize(t.begin(), (int)t.size()); |
213 | 0 | } |
214 | |
|
215 | 0 | Restart(); |
216 | 0 | } |
217 | | |
218 | | template <class T> |
219 | | void Poly1305_Base<T>::Update(const byte *input, size_t length) |
220 | 0 | { |
221 | 0 | CRYPTOPP_ASSERT((input && length) || !length); |
222 | 0 | if (!length) return; |
223 | | |
224 | 0 | size_t rem, num = m_idx; |
225 | 0 | if (num) |
226 | 0 | { |
227 | 0 | rem = BLOCKSIZE - num; |
228 | 0 | if (length >= rem) |
229 | 0 | { |
230 | | // Process |
231 | 0 | memcpy_s(m_acc + num, BLOCKSIZE - num, input, rem); |
232 | 0 | Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 1); |
233 | 0 | input += rem; length -= rem; |
234 | 0 | } |
235 | 0 | else |
236 | 0 | { |
237 | | // Accumulate |
238 | 0 | memcpy_s(m_acc + num, BLOCKSIZE - num, input, length); |
239 | 0 | m_idx = num + length; |
240 | 0 | return; |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | 0 | rem = length % BLOCKSIZE; |
245 | 0 | length -= rem; |
246 | |
|
247 | 0 | if (length >= BLOCKSIZE) { |
248 | 0 | Poly1305_HashBlocks(m_h, m_r, input, length, 1); |
249 | 0 | input += length; |
250 | 0 | } |
251 | |
|
252 | 0 | if (rem) |
253 | 0 | std::memcpy(m_acc, input, rem); |
254 | |
|
255 | 0 | m_idx = rem; |
256 | 0 | } |
257 | | |
258 | | template <class T> |
259 | | void Poly1305_Base<T>::TruncatedFinal(byte *mac, size_t size) |
260 | 0 | { |
261 | 0 | CRYPTOPP_ASSERT(mac); // Pointer is valid |
262 | 0 | CRYPTOPP_ASSERT(!m_used); // Nonce is fresh |
263 | |
|
264 | 0 | ThrowIfInvalidTruncatedSize(size); |
265 | |
|
266 | 0 | size_t num = m_idx; |
267 | 0 | if (num) |
268 | 0 | { |
269 | 0 | m_acc[num++] = 1; /* pad bit */ |
270 | 0 | while (num < BLOCKSIZE) |
271 | 0 | m_acc[num++] = 0; |
272 | 0 | Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 0); |
273 | 0 | } |
274 | |
|
275 | 0 | Poly1305_HashFinal(m_h, m_n, mac, size); |
276 | | |
277 | | // Restart |
278 | 0 | m_used = true; |
279 | 0 | Restart(); |
280 | 0 | } |
281 | | |
282 | | template <class T> |
283 | | void Poly1305_Base<T>::Resynchronize(const byte *nonce, int nonceLength) |
284 | 0 | { |
285 | 0 | CRYPTOPP_ASSERT(nonceLength == -1 || nonceLength == (int)BLOCKSIZE); |
286 | 0 | if (nonceLength == -1) { nonceLength = BLOCKSIZE; } |
287 | | |
288 | | // Encrypt the nonce, stash in m_nk |
289 | 0 | m_cipher.ProcessBlock(nonce, m_nk.begin()); |
290 | |
|
291 | 0 | m_n[0] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, m_nk + 0); |
292 | 0 | m_n[1] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, m_nk + 4); |
293 | 0 | m_n[2] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, m_nk + 8); |
294 | 0 | m_n[3] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, m_nk + 12); |
295 | | |
296 | | // Mark nonce as unused, meaning it is fresh |
297 | 0 | m_used = false; |
298 | 0 | } |
299 | | |
300 | | template <class T> |
301 | | void Poly1305_Base<T>::GetNextIV(RandomNumberGenerator &rng, byte *iv) |
302 | 0 | { |
303 | 0 | rng.GenerateBlock(iv, BLOCKSIZE); |
304 | 0 | } |
305 | | |
306 | | template <class T> |
307 | | void Poly1305_Base<T>::Restart() |
308 | 0 | { |
309 | 0 | m_h[0] = m_h[1] = m_h[2] = m_h[3] = m_h[4] = 0; |
310 | 0 | m_idx = 0; |
311 | 0 | } |
312 | | |
313 | | ////////////////////////////// IETF Poly1305 ////////////////////////////// |
314 | | |
315 | | void Poly1305TLS_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) |
316 | 36 | { |
317 | 36 | CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(length); |
318 | 36 | CRYPTOPP_ASSERT(key && length >= 32); |
319 | | |
320 | | // key is {r,s} pair. r is the additional key that gets clamped, s is the nonce. |
321 | 36 | m_r[0] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 0) & 0x0fffffff; |
322 | 36 | m_r[1] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 4) & 0x0ffffffc; |
323 | 36 | m_r[2] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 8) & 0x0ffffffc; |
324 | 36 | m_r[3] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 12) & 0x0ffffffc; |
325 | | |
326 | 36 | key += 16; |
327 | 36 | m_n[0] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 0); |
328 | 36 | m_n[1] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 4); |
329 | 36 | m_n[2] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 8); |
330 | 36 | m_n[3] = GetWord<word32>(false, LITTLE_ENDIAN_ORDER, key + 12); |
331 | | |
332 | 36 | Restart(); |
333 | 36 | } |
334 | | |
335 | | void Poly1305TLS_Base::Update(const byte *input, size_t length) |
336 | 68 | { |
337 | 68 | CRYPTOPP_ASSERT((input && length) || !length); |
338 | 68 | if (!length) return; |
339 | | |
340 | 59 | size_t rem, num = m_idx; |
341 | 59 | if (num) |
342 | 22 | { |
343 | 22 | rem = BLOCKSIZE - num; |
344 | 22 | if (length >= rem) |
345 | 22 | { |
346 | | // Process |
347 | 22 | memcpy_s(m_acc + num, BLOCKSIZE - num, input, rem); |
348 | 22 | Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 1); |
349 | 22 | input += rem; length -= rem; |
350 | 22 | } |
351 | 0 | else |
352 | 0 | { |
353 | | // Accumulate |
354 | 0 | memcpy_s(m_acc + num, BLOCKSIZE - num, input, length); |
355 | 0 | m_idx = num + length; |
356 | 0 | return; |
357 | 0 | } |
358 | 22 | } |
359 | | |
360 | 59 | rem = length % BLOCKSIZE; |
361 | 59 | length -= rem; |
362 | | |
363 | 59 | if (length >= BLOCKSIZE) { |
364 | 29 | Poly1305_HashBlocks(m_h, m_r, input, length, 1); |
365 | 29 | input += length; |
366 | 29 | } |
367 | | |
368 | 59 | if (rem) |
369 | 22 | std::memcpy(m_acc, input, rem); |
370 | | |
371 | 59 | m_idx = rem; |
372 | 59 | } |
373 | | |
374 | | void Poly1305TLS_Base::TruncatedFinal(byte *mac, size_t size) |
375 | 13 | { |
376 | 13 | CRYPTOPP_ASSERT(mac); // Pointer is valid |
377 | | |
378 | 13 | ThrowIfInvalidTruncatedSize(size); |
379 | | |
380 | 13 | size_t num = m_idx; |
381 | 13 | if (num) |
382 | 0 | { |
383 | 0 | m_acc[num++] = 1; /* pad bit */ |
384 | 0 | while (num < BLOCKSIZE) |
385 | 0 | m_acc[num++] = 0; |
386 | 0 | Poly1305_HashBlocks(m_h, m_r, m_acc, BLOCKSIZE, 0); |
387 | 0 | } |
388 | | |
389 | 13 | Poly1305_HashFinal(m_h, m_n, mac, size); |
390 | | |
391 | 13 | Restart(); |
392 | 13 | } |
393 | | |
394 | | void Poly1305TLS_Base::Restart() |
395 | 49 | { |
396 | 49 | m_h[0] = m_h[1] = m_h[2] = m_h[3] = m_h[4] = 0; |
397 | 49 | m_idx = 0; |
398 | 49 | } |
399 | | |
400 | | template class Poly1305_Base<AES>; |
401 | | template class Poly1305<AES>; |
402 | | |
403 | | NAMESPACE_END |