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