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