Coverage Report

Created: 2020-05-23 13:54

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