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