Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
69 void GHASH::ghash_update(secure_vector<uint8_t>& ghash,
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
120 void GHASH::add_final_block(secure_vector<uint8_t>& hash,
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
128 secure_vector<uint8_t> GHASH::final()
129 {
130 add_final_block(m_ghash, m_ad_len, m_text_len);
131
132 secure_vector<uint8_t> mac;
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
151 void GHASH::clear()
152 {
153 zeroise(m_H);
154 reset();
155 }
156
157 void GHASH::reset()
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
183 void GCM_Mode::clear()
184 {
185 m_ctr->clear();
186 m_ghash->clear();
187 reset();
188 }
189
190 void GCM_Mode::reset()
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
210 size_t GCM_Mode::update_granularity() const
211 {
212 return GCM_BS;
213 }
214
215 Key_Length_Specification GCM_Mode::key_spec() const
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 }
Botan::GHASH::reset
void reset()
Definition: gcm.cpp:157
Botan::xor_buf
void xor_buf(T out[], const T in[], size_t length)
Definition: mem_ops.h:115
Botan::GCM_Encryption::finish
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:270
Botan::GCM_Mode::provider
std::string provider() const override
Definition: gcm.cpp:200
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::GHASH::m_H
secure_vector< uint8_t > m_H
Definition: gcm.h:144
Botan::GCM_Mode::name
std::string name() const override
Definition: gcm.cpp:195
Botan::GHASH::m_ghash
secure_vector< uint8_t > m_ghash
Definition: gcm.h:146
Botan::Exception
Definition: exceptn.h:21
Botan::GCM_Mode::m_ctr
std::unique_ptr< StreamCipher > m_ctr
Definition: gcm.h:52
Botan::GHASH::start
void start(const uint8_t nonce[], size_t len)
Definition: gcm.cpp:97
Botan::same_mem
bool same_mem(const T *p1, const T *p2, size_t n)
Definition: mem_ops.h:98
Botan::GHASH::add_final_block
void add_final_block(secure_vector< uint8_t > &x, size_t ad_len, size_t pt_len)
Definition: gcm.cpp:120
m_cipher_name
std::string m_cipher_name
Definition: openssl_block.cpp:53
Botan::GHASH
Definition: gcm.h:113
Botan::Integrity_Failure
Definition: exceptn.h:198
Botan::Key_Length_Specification
Definition: key_spec.h:18
Botan::CTR_BE
Definition: ctr.h:19
Botan::GHASH::nonce_hash
secure_vector< uint8_t > nonce_hash(const uint8_t nonce[], size_t len)
Definition: gcm.cpp:140
Botan::CT::poison
void poison(const T *p, size_t n)
Definition: ct_utils.h:46
Botan::GCM_Decryption::finish
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: gcm.cpp:290
Botan::GHASH::ghash_update
void ghash_update(secure_vector< uint8_t > &x, const uint8_t input[], size_t input_len)
Definition: gcm.cpp:69
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
Botan::Invalid_IV_Length
Definition: exceptn.h:109
Botan::GHASH::update
void update(const uint8_t in[], size_t len)
Definition: gcm.cpp:111
Botan::GCM_Mode::clear
void clear() override
Definition: gcm.cpp:183
Botan::GCM_Mode::update_granularity
size_t update_granularity() const override
Definition: gcm.cpp:210
Botan::GCM_Mode::m_tag_size
const size_t m_tag_size
Definition: gcm.h:49
BOTAN_ASSERT
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
Botan::GCM_Mode::GCM_Mode
GCM_Mode(BlockCipher *cipher, size_t tag_size)
Definition: gcm.cpp:168
Botan::gcm_multiply_clmul
void gcm_multiply_clmul(uint8_t x[16], const uint8_t H[16])
Definition: clmul.cpp:15
Botan::GCM_Mode::reset
void reset() override
Definition: gcm.cpp:190
Botan::load_be< uint64_t >
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:223
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:121
Botan::GCM_Encryption::process
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:262
Botan::GCM_Decryption::process
size_t process(uint8_t buf[], size_t size) override
Definition: gcm.cpp:282
Botan::GCM_Mode::m_cipher_name
const std::string m_cipher_name
Definition: gcm.h:50
Botan::GHASH::m_H_ad
secure_vector< uint8_t > m_H_ad
Definition: gcm.h:145
Botan::copy_mem
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:68
Botan
Definition: alg_id.cpp:13
Botan::GCM_Mode::tag_size
size_t tag_size() const override
Definition: gcm.h:37
Botan::GHASH::clear
void clear() override
Definition: gcm.cpp:151
Botan::GCM_Mode::m_ghash
std::unique_ptr< GHASH > m_ghash
Definition: gcm.h:53
Botan::GHASH::name
std::string name() const override
Definition: gcm.h:136
Botan::CT::min
T min(T a, T b)
Definition: ct_utils.h:180
Botan::GCM_Mode::set_associated_data
void set_associated_data(const uint8_t ad[], size_t ad_len) override
Definition: gcm.cpp:232
Botan::GHASH::m_ad_len
size_t m_ad_len
Definition: gcm.h:147
Botan::CT::unpoison
void unpoison(const T *p, size_t n)
Definition: ct_utils.h:57
Botan::GHASH::set_associated_data
void set_associated_data(const uint8_t ad[], size_t ad_len)
Definition: gcm.cpp:103
Botan::GHASH::final
secure_vector< uint8_t > final()
Definition: gcm.cpp:128
Botan::BlockCipher::block_size
virtual size_t block_size() const =0
hash
MechanismType hash
Definition: p11_mechanism.cpp:63
BOTAN_ARG_CHECK
#define BOTAN_ARG_CHECK(expr)
Definition: exceptn.h:44
Botan::GCM_Mode::valid_nonce_length
bool valid_nonce_length(size_t) const override
Definition: gcm.h:35
Botan::BlockCipher
Definition: block_cipher.h:19
Botan::zeroise
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:211
Botan::GCM_Mode::key_spec
Key_Length_Specification key_spec() const override
Definition: gcm.cpp:215