Botan  2.19.1
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/ghash.h>
11 #include <botan/block_cipher.h>
12 #include <botan/ctr.h>
13 
14 namespace Botan {
15 
16 /*
17 * GCM_Mode Constructor
18 */
19 GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) :
20  m_tag_size(tag_size),
21  m_cipher_name(cipher->name()),
22  m_ctr(new CTR_BE(cipher, 4)),
23  m_ghash(new GHASH)
24  {
25  if(cipher->block_size() != GCM_BS)
26  throw Invalid_Argument("Invalid block cipher for GCM");
27 
28  /* We allow any of the values 128, 120, 112, 104, or 96 bits as a tag size */
29  /* 64 bit tag is still supported but deprecated and will be removed in the future */
30  if(m_tag_size != 8 && (m_tag_size < 12 || m_tag_size > 16))
31  throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size));
32  }
33 
34 GCM_Mode::~GCM_Mode() { /* for unique_ptr */ }
35 
37  {
38  m_ctr->clear();
39  m_ghash->clear();
40  reset();
41  }
42 
44  {
45  m_ghash->reset();
46  }
47 
48 std::string GCM_Mode::name() const
49  {
50  return (m_cipher_name + "/GCM(" + std::to_string(tag_size()) + ")");
51  }
52 
53 std::string GCM_Mode::provider() const
54  {
55  return m_ghash->provider();
56  }
57 
59  {
60  return GCM_BS * std::max<size_t>(2, BOTAN_BLOCK_CIPHER_PAR_MULT);
61  }
62 
63 bool GCM_Mode::valid_nonce_length(size_t len) const
64  {
65  // GCM does not support empty nonces
66  return (len > 0);
67  }
68 
70  {
71  return m_ctr->key_spec();
72  }
73 
74 void GCM_Mode::key_schedule(const uint8_t key[], size_t keylen)
75  {
76  m_ctr->set_key(key, keylen);
77 
78  const std::vector<uint8_t> zeros(GCM_BS);
79  m_ctr->set_iv(zeros.data(), zeros.size());
80 
82  m_ctr->encipher(H);
83  m_ghash->set_key(H);
84  }
85 
86 void GCM_Mode::set_associated_data(const uint8_t ad[], size_t ad_len)
87  {
88  m_ghash->set_associated_data(ad, ad_len);
89  }
90 
91 void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
92  {
93  if(!valid_nonce_length(nonce_len))
94  throw Invalid_IV_Length(name(), nonce_len);
95 
96  if(m_y0.size() != GCM_BS)
97  m_y0.resize(GCM_BS);
98 
99  clear_mem(m_y0.data(), m_y0.size());
100 
101  if(nonce_len == 12)
102  {
103  copy_mem(m_y0.data(), nonce, nonce_len);
104  m_y0[15] = 1;
105  }
106  else
107  {
108  m_ghash->nonce_hash(m_y0, nonce, nonce_len);
109  }
110 
111  m_ctr->set_iv(m_y0.data(), m_y0.size());
112 
113  clear_mem(m_y0.data(), m_y0.size());
114  m_ctr->encipher(m_y0);
115 
116  m_ghash->start(m_y0.data(), m_y0.size());
117  clear_mem(m_y0.data(), m_y0.size());
118  }
119 
120 size_t GCM_Encryption::process(uint8_t buf[], size_t sz)
121  {
122  BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size");
123  m_ctr->cipher(buf, buf, sz);
124  m_ghash->update(buf, sz);
125  return sz;
126  }
127 
128 void GCM_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
129  {
130  BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
131  const size_t sz = buffer.size() - offset;
132  uint8_t* buf = buffer.data() + offset;
133 
134  m_ctr->cipher(buf, buf, sz);
135  m_ghash->update(buf, sz);
136 
137  uint8_t mac[16] = { 0 };
138  m_ghash->final(mac, tag_size());
139  buffer += std::make_pair(mac, tag_size());
140  }
141 
142 size_t GCM_Decryption::process(uint8_t buf[], size_t sz)
143  {
144  BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size");
145  m_ghash->update(buf, sz);
146  m_ctr->cipher(buf, buf, sz);
147  return sz;
148  }
149 
150 void GCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
151  {
152  BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
153  const size_t sz = buffer.size() - offset;
154  uint8_t* buf = buffer.data() + offset;
155 
156  if(sz < tag_size())
157  throw Decoding_Error("Insufficient input for GCM decryption, tag missing");
158 
159  const size_t remaining = sz - tag_size();
160 
161  // handle any final input before the tag
162  if(remaining)
163  {
164  m_ghash->update(buf, remaining);
165  m_ctr->cipher(buf, buf, remaining);
166  }
167 
168  uint8_t mac[16] = { 0 };
169  m_ghash->final(mac, tag_size());
170 
171  const uint8_t* included_tag = &buffer[remaining+offset];
172 
173  if(!constant_time_compare(mac, included_tag, tag_size()))
174  throw Invalid_Authentication_Tag("GCM tag check failed");
175 
176  buffer.resize(offset + remaining);
177  }
178 
179 }
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:128
std::string provider() const override
Definition: gcm.cpp:53
SIMD_8x32 H
std::string name() const override
Definition: gcm.cpp:48
std::unique_ptr< StreamCipher > m_ctr
Definition: gcm.h:56
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:150
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
void clear() override
Definition: gcm.cpp:36
std::string m_cipher_name
size_t update_granularity() const override
Definition: gcm.cpp:58
const size_t m_tag_size
Definition: gcm.h:53
GCM_Mode(BlockCipher *cipher, size_t tag_size)
Definition: gcm.cpp:19
void reset() override
Definition: gcm.cpp:43
std::string name
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:65
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:120
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:142
const std::string m_cipher_name
Definition: gcm.h:54
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
Definition: alg_id.cpp:13
size_t tag_size() const override
Definition: gcm.h:39
#define BOTAN_ARG_CHECK(expr, msg)
Definition: assert.h:37
std::unique_ptr< GHASH > m_ghash
Definition: gcm.h:57
static const size_t GCM_BS
Definition: gcm.h:51
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: gcm.cpp:86
bool valid_nonce_length(size_t len) const override
Definition: gcm.cpp:63
virtual size_t block_size() const =0
Key_Length_Specification key_spec() const override
Definition: gcm.cpp:69