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