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