Coverage Report

Created: 2023-01-25 06:35

/src/botan/src/lib/utils/ghash/ghash.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* GCM GHASH
3
* (C) 2013,2015,2017 Jack Lloyd
4
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/internal/ghash.h>
10
#include <botan/internal/ct_utils.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/cpuid.h>
13
#include <botan/exceptn.h>
14
15
namespace Botan {
16
17
std::string GHASH::provider() const
18
0
   {
19
0
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
20
0
   if(CPUID::has_carryless_multiply())
21
0
      return "clmul";
22
0
#endif
23
24
0
#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
25
0
   if(CPUID::has_vperm())
26
0
      return "vperm";
27
0
#endif
28
29
0
   return "base";
30
0
   }
31
32
void GHASH::ghash_multiply(secure_vector<uint8_t>& x,
33
                         const uint8_t input[],
34
                         size_t blocks)
35
1.75k
   {
36
1.75k
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
37
1.75k
   if(CPUID::has_carryless_multiply())
38
1.75k
      {
39
1.75k
      return ghash_multiply_cpu(x.data(), m_H_pow.data(), input, blocks);
40
1.75k
      }
41
0
#endif
42
43
0
#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
44
0
   if(CPUID::has_vperm())
45
0
      {
46
0
      return ghash_multiply_vperm(x.data(), m_HM.data(), input, blocks);
47
0
      }
48
0
#endif
49
50
0
   CT::poison(x.data(), x.size());
51
52
0
   const uint64_t ALL_BITS = 0xFFFFFFFFFFFFFFFF;
53
54
0
   uint64_t X[2] = {
55
0
      load_be<uint64_t>(x.data(), 0),
56
0
      load_be<uint64_t>(x.data(), 1)
57
0
   };
58
59
0
   for(size_t b = 0; b != blocks; ++b)
60
0
      {
61
0
      X[0] ^= load_be<uint64_t>(input, 2*b);
62
0
      X[1] ^= load_be<uint64_t>(input, 2*b+1);
63
64
0
      uint64_t Z[2] = { 0, 0 };
65
66
0
      for(size_t i = 0; i != 64; ++i)
67
0
         {
68
0
         const uint64_t X0MASK = (ALL_BITS + (X[0] >> 63)) ^ ALL_BITS;
69
0
         const uint64_t X1MASK = (ALL_BITS + (X[1] >> 63)) ^ ALL_BITS;
70
71
0
         X[0] <<= 1;
72
0
         X[1] <<= 1;
73
74
0
         Z[0] ^= m_HM[4*i  ] & X0MASK;
75
0
         Z[1] ^= m_HM[4*i+1] & X0MASK;
76
0
         Z[0] ^= m_HM[4*i+2] & X1MASK;
77
0
         Z[1] ^= m_HM[4*i+3] & X1MASK;
78
0
         }
79
80
0
      X[0] = Z[0];
81
0
      X[1] = Z[1];
82
0
      }
83
84
0
   store_be<uint64_t>(x.data(), X[0], X[1]);
85
0
   CT::unpoison(x.data(), x.size());
86
0
   }
87
88
void GHASH::ghash_update(secure_vector<uint8_t>& ghash,
89
                         const uint8_t input[], size_t length)
90
1.28k
   {
91
1.28k
   verify_key_set(!m_HM.empty());
92
93
   /*
94
   This assumes if less than block size input then we're just on the
95
   final block and should pad with zeros
96
   */
97
98
1.28k
   const size_t full_blocks = length / GCM_BS;
99
1.28k
   const size_t final_bytes = length - (full_blocks * GCM_BS);
100
101
1.28k
   if(full_blocks > 0)
102
987
      {
103
987
      ghash_multiply(ghash, input, full_blocks);
104
987
      }
105
106
1.28k
   if(final_bytes)
107
763
      {
108
763
      uint8_t last_block[GCM_BS] = { 0 };
109
763
      copy_mem(last_block, input + full_blocks * GCM_BS, final_bytes);
110
763
      ghash_multiply(ghash, last_block, 1);
111
763
      secure_scrub_memory(last_block, final_bytes);
112
763
      }
113
1.28k
   }
114
115
void GHASH::key_schedule(const uint8_t key[], size_t length)
116
398
   {
117
398
   m_H.assign(key, key+length);
118
398
   m_H_ad.resize(GCM_BS);
119
398
   m_ad_len = 0;
120
398
   m_text_len = 0;
121
122
398
   uint64_t H0 = load_be<uint64_t>(m_H.data(), 0);
123
398
   uint64_t H1 = load_be<uint64_t>(m_H.data(), 1);
124
125
398
   const uint64_t R = 0xE100000000000000;
126
127
398
   m_HM.resize(256);
128
129
   // precompute the multiples of H
130
1.19k
   for(size_t i = 0; i != 2; ++i)
131
796
      {
132
51.7k
      for(size_t j = 0; j != 64; ++j)
133
50.9k
         {
134
         /*
135
         we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68
136
         to make indexing nicer in the multiplication code
137
         */
138
50.9k
         m_HM[4*j+2*i] = H0;
139
50.9k
         m_HM[4*j+2*i+1] = H1;
140
141
         // GCM's bit ops are reversed so we carry out of the bottom
142
50.9k
         const uint64_t carry = R * (H1 & 1);
143
50.9k
         H1 = (H1 >> 1) | (H0 << 63);
144
50.9k
         H0 = (H0 >> 1) ^ carry;
145
50.9k
         }
146
796
      }
147
148
398
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
149
398
   if(CPUID::has_carryless_multiply())
150
398
      {
151
398
      m_H_pow.resize(8);
152
398
      ghash_precompute_cpu(m_H.data(), m_H_pow.data());
153
398
      }
154
398
#endif
155
398
   }
156
157
void GHASH::start(const uint8_t nonce[], size_t len)
158
428
   {
159
428
   BOTAN_ARG_CHECK(len == 16, "GHASH requires a 128-bit nonce");
160
428
   m_nonce.assign(nonce, nonce + len);
161
428
   m_ghash = m_H_ad;
162
428
   }
163
164
void GHASH::set_associated_data(const uint8_t input[], size_t length)
165
428
   {
166
428
   if(m_ghash.empty() == false)
167
0
      throw Invalid_State("Too late to set AD in GHASH");
168
169
428
   zeroise(m_H_ad);
170
171
428
   ghash_update(m_H_ad, input, length);
172
428
   m_ad_len = length;
173
428
   }
174
175
void GHASH::update_associated_data(const uint8_t ad[], size_t length)
176
0
   {
177
0
   verify_key_set(m_ghash.size() == GCM_BS);
178
0
   m_ad_len += length;
179
0
   ghash_update(m_ghash, ad, length);
180
0
   }
181
182
void GHASH::update(const uint8_t input[], size_t length)
183
427
   {
184
427
   verify_key_set(m_ghash.size() == GCM_BS);
185
427
   m_text_len += length;
186
427
   ghash_update(m_ghash, input, length);
187
427
   }
188
189
void GHASH::add_final_block(secure_vector<uint8_t>& hash,
190
                            size_t ad_len, size_t text_len)
191
428
   {
192
   /*
193
   * stack buffer is fine here since the text len is public
194
   * and the length of the AD is probably not sensitive either.
195
   */
196
428
   uint8_t final_block[GCM_BS];
197
428
   store_be<uint64_t>(final_block, 8*ad_len, 8*text_len);
198
428
   ghash_update(hash, final_block, GCM_BS);
199
428
   }
200
201
void GHASH::final(uint8_t mac[], size_t mac_len)
202
428
   {
203
428
   BOTAN_ARG_CHECK(mac_len > 0 && mac_len <= 16, "GHASH output length");
204
205
428
   verify_key_set(m_ghash.size() == GCM_BS);
206
428
   add_final_block(m_ghash, m_ad_len, m_text_len);
207
208
7.27k
   for(size_t i = 0; i != mac_len; ++i)
209
6.84k
      mac[i] = m_ghash[i] ^ m_nonce[i];
210
211
428
   m_ghash.clear();
212
428
   m_text_len = 0;
213
428
   }
214
215
void GHASH::nonce_hash(secure_vector<uint8_t>& y0, const uint8_t nonce[], size_t nonce_len)
216
0
   {
217
0
   BOTAN_ASSERT(m_ghash.empty(), "nonce_hash called during wrong time");
218
219
0
   ghash_update(y0, nonce, nonce_len);
220
0
   add_final_block(y0, 0, nonce_len);
221
0
   }
222
223
void GHASH::clear()
224
0
   {
225
0
   zap(m_H);
226
0
   zap(m_HM);
227
0
   reset();
228
0
   }
229
230
void GHASH::reset()
231
0
   {
232
0
   zeroise(m_H_ad);
233
0
   m_ghash.clear();
234
0
   m_nonce.clear();
235
0
   m_text_len = m_ad_len = 0;
236
0
   }
237
238
}