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