Coverage Report

Created: 2020-06-30 13:58

/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
4.12k
   {
44
4.12k
#if defined(BOTAN_HAS_GCM_CLMUL_CPU)
45
4.12k
   if(CPUID::has_carryless_multiply())
46
4.12k
      {
47
4.12k
      return gcm_multiply_clmul(x.data(), m_H_pow.data(), input, blocks);
48
4.12k
      }
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.37k
   {
99
3.37k
   verify_key_set(!m_HM.empty());
100
3.37k
101
3.37k
   /*
102
3.37k
   This assumes if less than block size input then we're just on the
103
3.37k
   final block and should pad with zeros
104
3.37k
   */
105
3.37k
106
3.37k
   const size_t full_blocks = length / GCM_BS;
107
3.37k
   const size_t final_bytes = length - (full_blocks * GCM_BS);
108
3.37k
109
3.37k
   if(full_blocks > 0)
110
2.27k
      {
111
2.27k
      gcm_multiply(ghash, input, full_blocks);
112
2.27k
      }
113
3.37k
114
3.37k
   if(final_bytes)
115
1.85k
      {
116
1.85k
      uint8_t last_block[GCM_BS] = { 0 };
117
1.85k
      copy_mem(last_block, input + full_blocks * GCM_BS, final_bytes);
118
1.85k
      gcm_multiply(ghash, last_block, 1);
119
1.85k
      secure_scrub_memory(last_block, final_bytes);
120
1.85k
      }
121
3.37k
   }
122
123
void GHASH::key_schedule(const uint8_t key[], size_t length)
124
943
   {
125
943
   m_H.assign(key, key+length);
126
943
   m_H_ad.resize(GCM_BS);
127
943
   m_ad_len = 0;
128
943
   m_text_len = 0;
129
943
130
943
   uint64_t H0 = load_be<uint64_t>(m_H.data(), 0);
131
943
   uint64_t H1 = load_be<uint64_t>(m_H.data(), 1);
132
943
133
943
   const uint64_t R = 0xE100000000000000;
134
943
135
943
   m_HM.resize(256);
136
943
137
943
   // precompute the multiples of H
138
2.82k
   for(size_t i = 0; i != 2; ++i)
139
1.88k
      {
140
122k
      for(size_t j = 0; j != 64; ++j)
141
120k
         {
142
120k
         /*
143
120k
         we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68
144
120k
         to make indexing nicer in the multiplication code
145
120k
         */
146
120k
         m_HM[4*j+2*i] = H0;
147
120k
         m_HM[4*j+2*i+1] = H1;
148
120k
149
120k
         // GCM's bit ops are reversed so we carry out of the bottom
150
120k
         const uint64_t carry = R * (H1 & 1);
151
120k
         H1 = (H1 >> 1) | (H0 << 63);
152
120k
         H0 = (H0 >> 1) ^ carry;
153
120k
         }
154
1.88k
      }
155
943
156
943
#if defined(BOTAN_HAS_GCM_CLMUL_CPU)
157
943
   if(CPUID::has_carryless_multiply())
158
943
      {
159
943
      m_H_pow.resize(8);
160
943
      gcm_clmul_precompute(m_H.data(), m_H_pow.data());
161
943
      }
162
943
#endif
163
943
   }
164
165
void GHASH::start(const uint8_t nonce[], size_t len)
166
1.12k
   {
167
1.12k
   BOTAN_ARG_CHECK(len == 16, "GHASH requires a 128-bit nonce");
168
1.12k
   m_nonce.assign(nonce, nonce + len);
169
1.12k
   m_ghash = m_H_ad;
170
1.12k
   }
171
172
void GHASH::set_associated_data(const uint8_t input[], size_t length)
173
1.12k
   {
174
1.12k
   if(m_ghash.empty() == false)
175
0
      throw Invalid_State("Too late to set AD in GHASH");
176
1.12k
177
1.12k
   zeroise(m_H_ad);
178
1.12k
179
1.12k
   ghash_update(m_H_ad, input, length);
180
1.12k
   m_ad_len = length;
181
1.12k
   }
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.12k
   {
192
1.12k
   verify_key_set(m_ghash.size() == GCM_BS);
193
1.12k
   m_text_len += length;
194
1.12k
   ghash_update(m_ghash, input, length);
195
1.12k
   }
196
197
void GHASH::add_final_block(secure_vector<uint8_t>& hash,
198
                            size_t ad_len, size_t text_len)
199
1.12k
   {
200
1.12k
   /*
201
1.12k
   * stack buffer is fine here since the text len is public
202
1.12k
   * and the length of the AD is probably not sensitive either.
203
1.12k
   */
204
1.12k
   uint8_t final_block[GCM_BS];
205
1.12k
   store_be<uint64_t>(final_block, 8*ad_len, 8*text_len);
206
1.12k
   ghash_update(hash, final_block, GCM_BS);
207
1.12k
   }
208
209
void GHASH::final(uint8_t mac[], size_t mac_len)
210
1.12k
   {
211
1.12k
   BOTAN_ARG_CHECK(mac_len > 0 && mac_len <= 16, "GHASH output length");
212
1.12k
   add_final_block(m_ghash, m_ad_len, m_text_len);
213
1.12k
214
19.1k
   for(size_t i = 0; i != mac_len; ++i)
215
18.0k
      mac[i] = m_ghash[i] ^ m_nonce[i];
216
1.12k
217
1.12k
   m_ghash.clear();
218
1.12k
   m_text_len = 0;
219
1.12k
   }
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
}