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