Coverage Report

Created: 2024-11-21 07:03

/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 &params)
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 &params)
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