Botan  2.1.0
Crypto and TLS for C++11
gcm.cpp
Go to the documentation of this file.
1 /*
2 * GCM Mode Encryption
3 * (C) 2013,2015 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/gcm.h>
10 #include <botan/internal/ct_utils.h>
11 #include <botan/loadstor.h>
12 #include <botan/ctr.h>
13 
14 #if defined(BOTAN_HAS_GCM_CLMUL)
15  #include <botan/internal/clmul.h>
16  #include <botan/cpuid.h>
17 #endif
18 
19 namespace Botan {
20 
21 static const size_t GCM_BS = 16;
22 
23 void GHASH::gcm_multiply(secure_vector<uint8_t>& x) const
24  {
25 #if defined(BOTAN_HAS_GCM_CLMUL)
26  if(CPUID::has_clmul())
27  return gcm_multiply_clmul(x.data(), m_H.data());
28 #endif
29 
30  static const uint64_t R = 0xE100000000000000;
31 
32  uint64_t H[2] = {
33  load_be<uint64_t>(m_H.data(), 0),
34  load_be<uint64_t>(m_H.data(), 1)
35  };
36 
37  uint64_t Z[2] = { 0, 0 };
38 
39  CT::poison(H, 2);
40  CT::poison(Z, 2);
41  CT::poison(x.data(), x.size());
42 
43  // SSE2 might be useful here
44 
45  for(size_t i = 0; i != 2; ++i)
46  {
47  const uint64_t X = load_be<uint64_t>(x.data(), i);
48 
49  uint64_t mask = 0x8000000000000000;
50  for(size_t j = 0; j != 64; ++j)
51  {
52  const uint64_t XMASK = CT::expand_mask<uint64_t>(X & mask);
53  mask >>= 1;
54  Z[0] ^= H[0] & XMASK;
55  Z[1] ^= H[1] & XMASK;
56 
57  // GCM's bit ops are reversed so we carry out of the bottom
58  const uint64_t carry = R & CT::expand_mask<uint64_t>(H[1] & 1);
59 
60  H[1] = (H[1] >> 1) | (H[0] << 63);
61  H[0] = (H[0] >> 1) ^ carry;
62  }
63  }
64 
65  store_be<uint64_t>(x.data(), Z[0], Z[1]);
66  CT::unpoison(x.data(), x.size());
67  }
68 
70  const uint8_t input[], size_t length)
71  {
72  /*
73  This assumes if less than block size input then we're just on the
74  final block and should pad with zeros
75  */
76  while(length)
77  {
78  const size_t to_proc = std::min(length, GCM_BS);
79 
80  xor_buf(ghash.data(), input, to_proc);
81 
82  gcm_multiply(ghash);
83 
84  input += to_proc;
85  length -= to_proc;
86  }
87  }
88 
89 void GHASH::key_schedule(const uint8_t key[], size_t length)
90  {
91  m_H.assign(key, key+length);
92  m_H_ad.resize(GCM_BS);
93  m_ad_len = 0;
94  m_text_len = 0;
95  }
96 
97 void GHASH::start(const uint8_t nonce[], size_t len)
98  {
99  m_nonce.assign(nonce, nonce + len);
100  m_ghash = m_H_ad;
101  }
102 
103 void GHASH::set_associated_data(const uint8_t input[], size_t length)
104  {
105  zeroise(m_H_ad);
106 
107  ghash_update(m_H_ad, input, length);
108  m_ad_len = length;
109  }
110 
111 void GHASH::update(const uint8_t input[], size_t length)
112  {
113  BOTAN_ASSERT(m_ghash.size() == GCM_BS, "Key was set");
114 
115  m_text_len += length;
116 
117  ghash_update(m_ghash, input, length);
118  }
119 
121  size_t ad_len, size_t text_len)
122  {
123  secure_vector<uint8_t> final_block(GCM_BS);
124  store_be<uint64_t>(final_block.data(), 8*ad_len, 8*text_len);
125  ghash_update(hash, final_block.data(), final_block.size());
126  }
127 
129  {
130  add_final_block(m_ghash, m_ad_len, m_text_len);
131 
133  mac.swap(m_ghash);
134 
135  mac ^= m_nonce;
136  m_text_len = 0;
137  return mac;
138  }
139 
140 secure_vector<uint8_t> GHASH::nonce_hash(const uint8_t nonce[], size_t nonce_len)
141  {
142  BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time");
143  secure_vector<uint8_t> y0(GCM_BS);
144 
145  ghash_update(y0, nonce, nonce_len);
146  add_final_block(y0, 0, nonce_len);
147 
148  return y0;
149  }
150 
152  {
153  zeroise(m_H);
154  reset();
155  }
156 
158  {
159  zeroise(m_H_ad);
160  m_ghash.clear();
161  m_nonce.clear();
162  m_text_len = m_ad_len = 0;
163  }
164 
165 /*
166 * GCM_Mode Constructor
167 */
168 GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) :
169  m_tag_size(tag_size),
170  m_cipher_name(cipher->name())
171  {
172  if(cipher->block_size() != GCM_BS)
173  throw Invalid_Argument("Invalid block cipher for GCM");
174 
175  m_ghash.reset(new GHASH);
176 
177  m_ctr.reset(new CTR_BE(cipher, 4)); // CTR_BE takes ownership of cipher
178 
179  if(m_tag_size != 8 && m_tag_size != GCM_BS)
180  throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size));
181  }
182 
184  {
185  m_ctr->clear();
186  m_ghash->clear();
187  reset();
188  }
189 
191  {
192  m_ghash->reset();
193  }
194 
195 std::string GCM_Mode::name() const
196  {
197  return (m_cipher_name + "/GCM(" + std::to_string(tag_size()) + ")");
198  }
199 
200 std::string GCM_Mode::provider() const
201  {
202 #if defined(BOTAN_HAS_GCM_CLMUL)
203  if(CPUID::has_clmul())
204  return "clmul";
205 #endif
206 
207  return "base";
208  }
209 
211  {
212  return GCM_BS;
213  }
214 
216  {
217  return m_ctr->key_spec();
218  }
219 
220 void GCM_Mode::key_schedule(const uint8_t key[], size_t keylen)
221  {
222  m_ctr->set_key(key, keylen);
223 
224  const std::vector<uint8_t> zeros(GCM_BS);
225  m_ctr->set_iv(zeros.data(), zeros.size());
226 
227  secure_vector<uint8_t> H(GCM_BS);
228  m_ctr->encipher(H);
229  m_ghash->set_key(H);
230  }
231 
232 void GCM_Mode::set_associated_data(const uint8_t ad[], size_t ad_len)
233  {
234  m_ghash->set_associated_data(ad, ad_len);
235  }
236 
237 void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
238  {
239  if(!valid_nonce_length(nonce_len))
240  throw Invalid_IV_Length(name(), nonce_len);
241 
242  secure_vector<uint8_t> y0(GCM_BS);
243 
244  if(nonce_len == 12)
245  {
246  copy_mem(y0.data(), nonce, nonce_len);
247  y0[15] = 1;
248  }
249  else
250  {
251  y0 = m_ghash->nonce_hash(nonce, nonce_len);
252  }
253 
254  m_ctr->set_iv(y0.data(), y0.size());
255 
256  secure_vector<uint8_t> m_enc_y0(GCM_BS);
257  m_ctr->encipher(m_enc_y0);
258 
259  m_ghash->start(m_enc_y0.data(), m_enc_y0.size());
260  }
261 
262 size_t GCM_Encryption::process(uint8_t buf[], size_t sz)
263  {
264  BOTAN_ARG_CHECK(sz % update_granularity() == 0);
265  m_ctr->cipher(buf, buf, sz);
266  m_ghash->update(buf, sz);
267  return sz;
268  }
269 
270 void GCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
271  {
272  BOTAN_ARG_CHECK(offset <= buffer.size());
273  const size_t sz = buffer.size() - offset;
274  uint8_t* buf = buffer.data() + offset;
275 
276  m_ctr->cipher(buf, buf, sz);
277  m_ghash->update(buf, sz);
278  auto mac = m_ghash->final();
279  buffer += std::make_pair(mac.data(), tag_size());
280  }
281 
282 size_t GCM_Decryption::process(uint8_t buf[], size_t sz)
283  {
284  BOTAN_ARG_CHECK(sz % update_granularity() == 0);
285  m_ghash->update(buf, sz);
286  m_ctr->cipher(buf, buf, sz);
287  return sz;
288  }
289 
290 void GCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
291  {
292  BOTAN_ARG_CHECK(offset <= buffer.size());
293  const size_t sz = buffer.size() - offset;
294  uint8_t* buf = buffer.data() + offset;
295 
296  if(sz < tag_size())
297  throw Exception("Insufficient input for GCM decryption, tag missing");
298 
299  const size_t remaining = sz - tag_size();
300 
301  // handle any final input before the tag
302  if(remaining)
303  {
304  m_ghash->update(buf, remaining);
305  m_ctr->cipher(buf, buf, remaining);
306  }
307 
308  auto mac = m_ghash->final();
309 
310  const uint8_t* included_tag = &buffer[remaining+offset];
311 
312  if(!same_mem(mac.data(), included_tag, tag_size()))
313  throw Integrity_Failure("GCM tag check failed");
314 
315  buffer.resize(offset + remaining);
316  }
317 
318 }
void reset()
Definition: gcm.cpp:157
void xor_buf(T out[], const T in[], size_t length)
Definition: mem_ops.h:115
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:270
std::string provider() const override
Definition: gcm.cpp:200
secure_vector< uint8_t > m_H
Definition: gcm.h:144
std::string name() const override
Definition: gcm.cpp:195
secure_vector< uint8_t > m_ghash
Definition: gcm.h:146
std::unique_ptr< StreamCipher > m_ctr
Definition: gcm.h:52
void start(const uint8_t nonce[], size_t len)
Definition: gcm.cpp:97
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
void add_final_block(secure_vector< uint8_t > &x, size_t ad_len, size_t pt_len)
Definition: gcm.cpp:120
std::string m_cipher_name
secure_vector< uint8_t > nonce_hash(const uint8_t nonce[], size_t len)
Definition: gcm.cpp:140
void poison(const T *p, size_t n)
Definition: ct_utils.h:46
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:290
void ghash_update(secure_vector< uint8_t > &x, const uint8_t input[], size_t input_len)
Definition: gcm.cpp:69
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
void update(const uint8_t in[], size_t len)
Definition: gcm.cpp:111
void clear() override
Definition: gcm.cpp:183
size_t update_granularity() const override
Definition: gcm.cpp:210
const size_t m_tag_size
Definition: gcm.h:49
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
GCM_Mode(BlockCipher *cipher, size_t tag_size)
Definition: gcm.cpp:168
void gcm_multiply_clmul(uint8_t x[16], const uint8_t H[16])
Definition: clmul.cpp:15
void reset() override
Definition: gcm.cpp:190
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:223
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:262
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:282
const std::string m_cipher_name
Definition: gcm.h:50
secure_vector< uint8_t > m_H_ad
Definition: gcm.h:145
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:68
Definition: alg_id.cpp:13
size_t tag_size() const override
Definition: gcm.h:37
void clear() override
Definition: gcm.cpp:151
std::unique_ptr< GHASH > m_ghash
Definition: gcm.h:53
std::string name() const override
Definition: gcm.h:136
T min(T a, T b)
Definition: ct_utils.h:180
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: gcm.cpp:232
size_t m_ad_len
Definition: gcm.h:147
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: gcm.cpp:103
secure_vector< uint8_t > final()
Definition: gcm.cpp:128
virtual size_t block_size() const =0
MechanismType hash
#define BOTAN_ARG_CHECK(expr)
Definition: exceptn.h:44
bool valid_nonce_length(size_t) const override
Definition: gcm.h:35
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:211
Key_Length_Specification key_spec() const override
Definition: gcm.cpp:215