Botan 3.6.1
Crypto and TLS for C&
ghash.cpp
Go to the documentation of this file.
1/*
2* GCM GHASH
3* (C) 2013,2015,2017 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/ghash.h>
10
11#include <botan/exceptn.h>
12#include <botan/internal/cpuid.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/loadstor.h>
15
16#include <array>
17
18namespace Botan {
19
20std::string GHASH::provider() const {
21#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
23 return "clmul";
24 }
25#endif
26
27#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
28 if(CPUID::has_vperm()) {
29 return "vperm";
30 }
31#endif
32
33 return "base";
34}
35
36void GHASH::ghash_multiply(secure_vector<uint8_t>& x, std::span<const uint8_t> input, size_t blocks) {
37#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
39 BOTAN_ASSERT_NOMSG(!m_H_pow.empty());
40 return ghash_multiply_cpu(x.data(), m_H_pow.data(), input.data(), blocks);
41 }
42#endif
43
44#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
45 if(CPUID::has_vperm()) {
46 return ghash_multiply_vperm(x.data(), m_HM.data(), input.data(), blocks);
47 }
48#endif
49
50 CT::poison(x.data(), x.size());
51
52 uint64_t X[2] = {load_be<uint64_t>(x.data(), 0), load_be<uint64_t>(x.data(), 1)};
53
54 for(size_t b = 0; b != blocks; ++b) {
55 X[0] ^= load_be<uint64_t>(input.data(), 2 * b);
56 X[1] ^= load_be<uint64_t>(input.data(), 2 * b + 1);
57
58 uint64_t Z[2] = {0, 0};
59
60 for(size_t i = 0; i != 64; ++i) {
61 const auto X0MASK = CT::Mask<uint64_t>::expand_top_bit(X[0]);
62 const auto X1MASK = CT::Mask<uint64_t>::expand_top_bit(X[1]);
63
64 X[0] <<= 1;
65 X[1] <<= 1;
66
67 Z[0] = X0MASK.select(Z[0] ^ m_HM[4 * i], Z[0]);
68 Z[1] = X0MASK.select(Z[1] ^ m_HM[4 * i + 1], Z[1]);
69
70 Z[0] = X1MASK.select(Z[0] ^ m_HM[4 * i + 2], Z[0]);
71 Z[1] = X1MASK.select(Z[1] ^ m_HM[4 * i + 3], Z[1]);
72 }
73
74 X[0] = Z[0];
75 X[1] = Z[1];
76 }
77
78 store_be<uint64_t>(x.data(), X[0], X[1]);
79 CT::unpoison(x.data(), x.size());
80}
81
82void GHASH::ghash_update(secure_vector<uint8_t>& ghash, std::span<const uint8_t> input) {
83 assert_key_material_set(!m_H.empty());
84
85 /*
86 This assumes if less than block size input then we're just on the
87 final block and should pad with zeros
88 */
89
90 const size_t full_blocks = input.size() / GCM_BS;
91 const size_t final_bytes = input.size() - (full_blocks * GCM_BS);
92
93 if(full_blocks > 0) {
94 ghash_multiply(ghash, input.first(full_blocks * GCM_BS), full_blocks);
95 }
96
97 if(final_bytes) {
98 uint8_t last_block[GCM_BS] = {0};
99 copy_mem(last_block, input.subspan(full_blocks * GCM_BS).data(), final_bytes);
100 ghash_multiply(ghash, last_block, 1);
101 secure_scrub_memory(last_block, final_bytes);
102 }
103}
104
106 return !m_ghash.empty();
107}
108
109void GHASH::key_schedule(std::span<const uint8_t> key) {
110 m_H.assign(key.begin(), key.end()); // TODO: C++23 - std::vector<>::assign_range()
111 m_H_ad.resize(GCM_BS);
112 m_ad_len = 0;
113 m_text_len = 0;
114
115 uint64_t H0 = load_be<uint64_t>(m_H.data(), 0);
116 uint64_t H1 = load_be<uint64_t>(m_H.data(), 1);
117
118 const uint64_t R = 0xE100000000000000;
119
120 m_HM.resize(256);
121
122 // precompute the multiples of H
123 for(size_t i = 0; i != 2; ++i) {
124 for(size_t j = 0; j != 64; ++j) {
125 /*
126 we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68
127 to make indexing nicer in the multiplication code
128 */
129 m_HM[4 * j + 2 * i] = H0;
130 m_HM[4 * j + 2 * i + 1] = H1;
131
132 // GCM's bit ops are reversed so we carry out of the bottom
133 const uint64_t carry = CT::Mask<uint64_t>::expand(H1 & 1).if_set_return(R);
134 H1 = (H1 >> 1) | (H0 << 63);
135 H0 = (H0 >> 1) ^ carry;
136 }
137 }
138
139#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
141 m_H_pow.resize(8);
142 ghash_precompute_cpu(m_H.data(), m_H_pow.data());
143 }
144#endif
145}
146
147void GHASH::start(std::span<const uint8_t> nonce) {
148 BOTAN_ARG_CHECK(nonce.size() == 16, "GHASH requires a 128-bit nonce");
149 m_nonce.assign(nonce.begin(), nonce.end()); // TODO: C++23: assign_range
150 m_ghash = m_H_ad;
151}
152
153void GHASH::set_associated_data(std::span<const uint8_t> input) {
154 if(m_ghash.empty() == false) {
155 throw Invalid_State("Too late to set AD in GHASH");
156 }
157
158 zeroise(m_H_ad);
159
160 ghash_update(m_H_ad, input);
161 m_ad_len = input.size();
162}
163
164void GHASH::update_associated_data(std::span<const uint8_t> ad) {
166 m_ad_len += ad.size();
167 ghash_update(m_ghash, ad);
168}
169
170void GHASH::update(std::span<const uint8_t> input) {
172 m_text_len += input.size();
173 ghash_update(m_ghash, input);
174}
175
176void GHASH::add_final_block(secure_vector<uint8_t>& hash, size_t ad_len, size_t text_len) {
177 /*
178 * stack buffer is fine here since the text len is public
179 * and the length of the AD is probably not sensitive either.
180 */
181 std::array<uint8_t, GCM_BS> final_block;
182
183 const uint64_t ad_bits = 8 * ad_len;
184 const uint64_t text_bits = 8 * text_len;
185 store_be(final_block, ad_bits, text_bits);
186 ghash_update(hash, final_block);
187}
188
189void GHASH::final(std::span<uint8_t> mac) {
190 BOTAN_ARG_CHECK(!mac.empty() && mac.size() <= 16, "GHASH output length");
191
193 add_final_block(m_ghash, m_ad_len, m_text_len);
194
195 for(size_t i = 0; i != mac.size(); ++i) {
196 mac[i] = m_ghash[i] ^ m_nonce[i];
197 }
198
199 m_ghash.clear();
200 m_text_len = 0;
201}
202
203void GHASH::nonce_hash(secure_vector<uint8_t>& y0, std::span<const uint8_t> nonce) {
204 BOTAN_ASSERT(m_ghash.empty(), "nonce_hash called during wrong time");
205
206 ghash_update(y0, nonce);
207 add_final_block(y0, 0, nonce.size());
208}
209
211 zap(m_H);
212 zap(m_HM);
213 reset();
214}
215
217 zeroise(m_H_ad);
218 m_ghash.clear();
219 m_nonce.clear();
220 m_text_len = m_ad_len = 0;
221}
222
223} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
static bool has_vperm()
Definition cpuid.h:335
static bool has_carryless_multiply()
Definition cpuid.h:366
static constexpr Mask< T > expand(T v)
Definition ct_utils.h:389
static constexpr Mask< T > expand_top_bit(T v)
Definition ct_utils.h:407
void update_associated_data(std::span< const uint8_t > ad)
Definition ghash.cpp:164
std::string provider() const
Definition ghash.cpp:20
void nonce_hash(secure_vector< uint8_t > &y0, std::span< const uint8_t > nonce)
Definition ghash.cpp:203
void ghash_update(secure_vector< uint8_t > &x, std::span< const uint8_t > input)
Definition ghash.cpp:82
void final(std::span< uint8_t > out)
Definition ghash.cpp:189
void add_final_block(secure_vector< uint8_t > &x, size_t ad_len, size_t pt_len)
Definition ghash.cpp:176
void clear() override
Definition ghash.cpp:210
void update(std::span< const uint8_t > in)
Definition ghash.cpp:170
void reset()
Definition ghash.cpp:216
void start(std::span< const uint8_t > nonce)
Definition ghash.cpp:147
bool has_keying_material() const override
Definition ghash.cpp:105
void set_associated_data(std::span< const uint8_t > ad)
Definition ghash.cpp:153
void assert_key_material_set() const
Definition sym_algo.h:139
FE_25519 Z
Definition ge.cpp:27
FE_25519 X
Definition ge.cpp:25
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:64
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:53
void zeroise(std::vector< T, Alloc > &vec)
Definition secmem.h:108
void zap(std::vector< T, Alloc > &vec)
Definition secmem.h:117
void secure_scrub_memory(void *ptr, size_t n)
Definition os_utils.cpp:83
void carry(int64_t &h0, int64_t &h1)
const SIMD_8x32 & b
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 auto store_be(ParamTs &&... params)
Definition loadstor.h:773
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:530