Botan 2.19.1
Crypto and TLS for C&
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
14namespace Botan {
15
16/*
17* GCM_Mode Constructor
18*/
19GCM_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
34GCM_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
48std::string GCM_Mode::name() const
49 {
50 return (m_cipher_name + "/GCM(" + std::to_string(tag_size()) + ")");
51 }
52
53std::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
63bool 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
74void 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
86void 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
91void 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
120size_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
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
142size_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
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}
#define BOTAN_ARG_CHECK(expr, msg)
Definition: assert.h:37
virtual size_t block_size() const =0
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:142
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:150
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:128
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:120
static const size_t GCM_BS
Definition: gcm.h:51
std::string name() const override
Definition: gcm.cpp:48
std::unique_ptr< GHASH > m_ghash
Definition: gcm.h:57
void reset() override
Definition: gcm.cpp:43
GCM_Mode(BlockCipher *cipher, size_t tag_size)
Definition: gcm.cpp:19
const size_t m_tag_size
Definition: gcm.h:53
std::string provider() const override
Definition: gcm.cpp:53
const std::string m_cipher_name
Definition: gcm.h:54
void clear() override
Definition: gcm.cpp:36
Key_Length_Specification key_spec() const override
Definition: gcm.cpp:69
size_t update_granularity() const override
Definition: gcm.cpp:58
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: gcm.cpp:86
std::unique_ptr< StreamCipher > m_ctr
Definition: gcm.h:56
size_t tag_size() const override
Definition: gcm.h:39
bool valid_nonce_length(size_t len) const override
Definition: gcm.cpp:63
std::string m_cipher_name
std::string name
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Definition: alg_id.cpp:13
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
bool constant_time_compare(const uint8_t x[], const uint8_t y[], size_t len)
Definition: mem_ops.h:82
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
void clear_mem(T *ptr, size_t n)
Definition: mem_ops.h:115