Coverage Report

Created: 2020-08-01 06:18

/src/botan/src/lib/mac/poly1305/poly1305.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Derived from poly1305-donna-64.h by Andrew Moon <liquidsun@gmail.com>
3
* in https://github.com/floodyberry/poly1305-donna
4
*
5
* (C) 2014 Andrew Moon
6
* (C) 2014 Jack Lloyd
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10
11
#include <botan/poly1305.h>
12
#include <botan/loadstor.h>
13
#include <botan/mul128.h>
14
#include <botan/internal/donna128.h>
15
#include <botan/internal/ct_utils.h>
16
17
namespace Botan {
18
19
namespace {
20
21
void poly1305_init(secure_vector<uint64_t>& X, const uint8_t key[32])
22
224
   {
23
224
   /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
24
224
   const uint64_t t0 = load_le<uint64_t>(key, 0);
25
224
   const uint64_t t1 = load_le<uint64_t>(key, 1);
26
224
27
224
   X[0] = ( t0                    ) & 0xffc0fffffff;
28
224
   X[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
29
224
   X[2] = ((t1 >> 24)             ) & 0x00ffffffc0f;
30
224
31
224
   /* h = 0 */
32
224
   X[3] = 0;
33
224
   X[4] = 0;
34
224
   X[5] = 0;
35
224
36
224
   /* save pad for later */
37
224
   X[6] = load_le<uint64_t>(key, 2);
38
224
   X[7] = load_le<uint64_t>(key, 3);
39
224
   }
40
41
void poly1305_blocks(secure_vector<uint64_t>& X, const uint8_t *m, size_t blocks, bool is_final = false)
42
716
   {
43
#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
44
   typedef donna128 uint128_t;
45
#endif
46
716
47
716
   const uint64_t hibit = is_final ? 0 : (static_cast<uint64_t>(1) << 40); /* 1 << 128 */
48
716
49
716
   const uint64_t r0 = X[0];
50
716
   const uint64_t r1 = X[1];
51
716
   const uint64_t r2 = X[2];
52
716
53
716
   const uint64_t M44 = 0xFFFFFFFFFFF;
54
716
   const uint64_t M42 = 0x3FFFFFFFFFF;
55
716
56
716
   uint64_t h0 = X[3+0];
57
716
   uint64_t h1 = X[3+1];
58
716
   uint64_t h2 = X[3+2];
59
716
60
716
   const uint64_t s1 = r1 * 20;
61
716
   const uint64_t s2 = r2 * 20;
62
716
63
6.07k
   for(size_t i = 0; i != blocks; ++i)
64
5.35k
      {
65
5.35k
      const uint64_t t0 = load_le<uint64_t>(m, 0);
66
5.35k
      const uint64_t t1 = load_le<uint64_t>(m, 1);
67
5.35k
68
5.35k
      h0 += (( t0                    ) & M44);
69
5.35k
      h1 += (((t0 >> 44) | (t1 << 20)) & M44);
70
5.35k
      h2 += (((t1 >> 24)             ) & M42) | hibit;
71
5.35k
72
5.35k
      const uint128_t d0 = uint128_t(h0) * r0 + uint128_t(h1) * s2 + uint128_t(h2) * s1;
73
5.35k
      const uint64_t c0 = carry_shift(d0, 44);
74
5.35k
75
5.35k
      const uint128_t d1 = uint128_t(h0) * r1 + uint128_t(h1) * r0 + uint128_t(h2) * s2 + c0;
76
5.35k
      const uint64_t c1 = carry_shift(d1, 44);
77
5.35k
78
5.35k
      const uint128_t d2 = uint128_t(h0) * r2 + uint128_t(h1) * r1 + uint128_t(h2) * r0 + c1;
79
5.35k
      const uint64_t c2 = carry_shift(d2, 42);
80
5.35k
81
5.35k
      h0 = d0 & M44;
82
5.35k
      h1 = d1 & M44;
83
5.35k
      h2 = d2 & M42;
84
5.35k
85
5.35k
      h0 += c2 * 5;
86
5.35k
      h1 += carry_shift(h0, 44);
87
5.35k
      h0 = h0 & M44;
88
5.35k
89
5.35k
      m += 16;
90
5.35k
      }
91
716
92
716
   X[3+0] = h0;
93
716
   X[3+1] = h1;
94
716
   X[3+2] = h2;
95
716
   }
96
97
void poly1305_finish(secure_vector<uint64_t>& X, uint8_t mac[16])
98
224
   {
99
224
   const uint64_t M44 = 0xFFFFFFFFFFF;
100
224
   const uint64_t M42 = 0x3FFFFFFFFFF;
101
224
102
224
   /* fully carry h */
103
224
   uint64_t h0 = X[3+0];
104
224
   uint64_t h1 = X[3+1];
105
224
   uint64_t h2 = X[3+2];
106
224
107
224
   uint64_t c;
108
224
                c = (h1 >> 44); h1 &= M44;
109
224
   h2 += c;     c = (h2 >> 42); h2 &= M42;
110
224
   h0 += c * 5; c = (h0 >> 44); h0 &= M44;
111
224
   h1 += c;     c = (h1 >> 44); h1 &= M44;
112
224
   h2 += c;     c = (h2 >> 42); h2 &= M42;
113
224
   h0 += c * 5; c = (h0 >> 44); h0 &= M44;
114
224
   h1 += c;
115
224
116
224
   /* compute h + -p */
117
224
   uint64_t g0 = h0 + 5; c = (g0 >> 44); g0 &= M44;
118
224
   uint64_t g1 = h1 + c; c = (g1 >> 44); g1 &= M44;
119
224
   uint64_t g2 = h2 + c - (static_cast<uint64_t>(1) << 42);
120
224
121
224
   /* select h if h < p, or h + -p if h >= p */
122
224
   const auto c_mask = CT::Mask<uint64_t>::expand(c);
123
224
   h0 = c_mask.select(g0, h0);
124
224
   h1 = c_mask.select(g1, h1);
125
224
   h2 = c_mask.select(g2, h2);
126
224
127
224
   /* h = (h + pad) */
128
224
   const uint64_t t0 = X[6];
129
224
   const uint64_t t1 = X[7];
130
224
131
224
   h0 += (( t0                    ) & M44)    ; c = (h0 >> 44); h0 &= M44;
132
224
   h1 += (((t0 >> 44) | (t1 << 20)) & M44) + c; c = (h1 >> 44); h1 &= M44;
133
224
   h2 += (((t1 >> 24)             ) & M42) + c;                 h2 &= M42;
134
224
135
224
   /* mac = h % (2^128) */
136
224
   h0 = ((h0      ) | (h1 << 44));
137
224
   h1 = ((h1 >> 20) | (h2 << 24));
138
224
139
224
   store_le(mac, h0, h1);
140
224
141
224
   /* zero out the state */
142
224
   clear_mem(X.data(), X.size());
143
224
   }
144
145
}
146
147
void Poly1305::clear()
148
0
   {
149
0
   zap(m_poly);
150
0
   zap(m_buf);
151
0
   m_buf_pos = 0;
152
0
   }
153
154
void Poly1305::key_schedule(const uint8_t key[], size_t)
155
224
   {
156
224
   m_buf_pos = 0;
157
224
   m_buf.resize(16);
158
224
   m_poly.resize(8);
159
224
160
224
   poly1305_init(m_poly, key);
161
224
   }
162
163
void Poly1305::add_data(const uint8_t input[], size_t length)
164
1.24k
   {
165
1.24k
   verify_key_set(m_poly.size() == 8);
166
1.24k
167
1.24k
   if(m_buf_pos)
168
573
      {
169
573
      buffer_insert(m_buf, m_buf_pos, input, length);
170
573
171
573
      if(m_buf_pos + length >= m_buf.size())
172
573
         {
173
573
         poly1305_blocks(m_poly, m_buf.data(), 1);
174
573
         input += (m_buf.size() - m_buf_pos);
175
573
         length -= (m_buf.size() - m_buf_pos);
176
573
         m_buf_pos = 0;
177
573
         }
178
573
      }
179
1.24k
180
1.24k
   const size_t full_blocks = length / m_buf.size();
181
1.24k
   const size_t remaining   = length % m_buf.size();
182
1.24k
183
1.24k
   if(full_blocks)
184
143
      poly1305_blocks(m_poly, input, full_blocks);
185
1.24k
186
1.24k
   buffer_insert(m_buf, m_buf_pos, input + full_blocks * m_buf.size(), remaining);
187
1.24k
   m_buf_pos += remaining;
188
1.24k
   }
189
190
void Poly1305::final_result(uint8_t out[])
191
224
   {
192
224
   verify_key_set(m_poly.size() == 8);
193
224
194
224
   if(m_buf_pos != 0)
195
0
      {
196
0
      m_buf[m_buf_pos] = 1;
197
0
      const size_t len = m_buf.size() - m_buf_pos - 1;
198
0
      if (len > 0)
199
0
         {
200
0
         clear_mem(&m_buf[m_buf_pos+1], len);
201
0
         }
202
0
      poly1305_blocks(m_poly, m_buf.data(), 1, true);
203
0
      }
204
224
205
224
   poly1305_finish(m_poly, out);
206
224
207
224
   m_poly.clear();
208
224
   m_buf_pos = 0;
209
224
   }
210
211
}