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