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