Botan 3.12.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 std::array<uint8_t, GCM_BS> y0 = {};
104
105 if(nonce_len == 12) {
106 copy_mem(y0.data(), nonce, nonce_len);
107 y0[15] = 1;
108 } else {
109 m_ghash->nonce_hash(std::span<uint8_t, GCM_BS>(y0), {nonce, nonce_len});
110 }
111
112 m_ctr->set_iv(y0.data(), y0.size());
113
114 clear_mem(y0.data(), y0.size());
115 m_ctr->encipher(y0);
116
117 m_ghash->start(y0);
119}
120
121size_t GCM_Encryption::process_msg(uint8_t buf[], size_t sz) {
122 BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size");
123 m_ctr->cipher(buf, buf, sz);
124 m_ghash->update({buf, sz});
125 return sz;
126}
127
128void GCM_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
129 BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
130 const size_t sz = buffer.size() - offset;
131 uint8_t* buf = buffer.data() + offset;
132
133 m_ctr->cipher(buf, buf, sz);
134 m_ghash->update({buf, sz});
135
136 std::array<uint8_t, 16> mac = {0};
137 m_ghash->final(std::span(mac).first(tag_size()));
138 buffer += std::make_pair(mac.data(), tag_size());
139}
140
141size_t GCM_Decryption::process_msg(uint8_t buf[], size_t sz) {
142 BOTAN_ARG_CHECK(sz % update_granularity() == 0, "Invalid buffer size");
143 m_ghash->update({buf, sz});
144 m_ctr->cipher(buf, buf, sz);
145 return sz;
146}
147
148void GCM_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
149 BOTAN_ARG_CHECK(offset <= buffer.size(), "Invalid offset");
150 const size_t sz = buffer.size() - offset;
151 uint8_t* buf = buffer.data() + offset;
152
153 BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
154
155 const size_t remaining = sz - tag_size();
156
157 // handle any final input before the tag
158 if(remaining > 0) {
159 m_ghash->update({buf, remaining});
160 m_ctr->cipher(buf, buf, remaining);
161 }
162
163 std::array<uint8_t, 16> mac = {0};
164 m_ghash->final(std::span(mac).first(tag_size()));
165
166 const uint8_t* included_tag = &buffer[remaining + offset];
167
168 if(!CT::is_equal(mac.data(), included_tag, tag_size()).as_bool()) {
169 clear_mem(std::span{buffer}.subspan(offset, remaining));
170 throw Invalid_Authentication_Tag("GCM tag check failed");
171 }
172
173 buffer.resize(offset + remaining);
174}
175
176} // 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
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:68
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118