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