Coverage Report

Created: 2023-06-07 07:00

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