Botan 2.19.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/ghash.h>
10#include <botan/internal/ct_utils.h>
11#include <botan/loadstor.h>
12#include <botan/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 verify_key_set(!m_HM.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
115void GHASH::key_schedule(const uint8_t key[], size_t length)
116 {
117 m_H.assign(key, key+length);
118 m_H_ad.resize(GCM_BS);
119 m_ad_len = 0;
120 m_text_len = 0;
121
122 uint64_t H0 = load_be<uint64_t>(m_H.data(), 0);
123 uint64_t H1 = load_be<uint64_t>(m_H.data(), 1);
124
125 const uint64_t R = 0xE100000000000000;
126
127 m_HM.resize(256);
128
129 // precompute the multiples of H
130 for(size_t i = 0; i != 2; ++i)
131 {
132 for(size_t j = 0; j != 64; ++j)
133 {
134 /*
135 we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68
136 to make indexing nicer in the multiplication code
137 */
138 m_HM[4*j+2*i] = H0;
139 m_HM[4*j+2*i+1] = H1;
140
141 // GCM's bit ops are reversed so we carry out of the bottom
142 const uint64_t carry = R * (H1 & 1);
143 H1 = (H1 >> 1) | (H0 << 63);
144 H0 = (H0 >> 1) ^ carry;
145 }
146 }
147
148#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
150 {
151 m_H_pow.resize(8);
152 ghash_precompute_cpu(m_H.data(), m_H_pow.data());
153 }
154#endif
155 }
156
157void GHASH::start(const uint8_t nonce[], size_t len)
158 {
159 BOTAN_ARG_CHECK(len == 16, "GHASH requires a 128-bit nonce");
160 m_nonce.assign(nonce, nonce + len);
161 m_ghash = m_H_ad;
162 }
163
164void GHASH::set_associated_data(const uint8_t input[], size_t length)
165 {
166 if(m_ghash.empty() == false)
167 throw Invalid_State("Too late to set AD in GHASH");
168
169 zeroise(m_H_ad);
170
171 ghash_update(m_H_ad, input, length);
172 m_ad_len = length;
173 }
174
175void GHASH::update_associated_data(const uint8_t ad[], size_t length)
176 {
177 verify_key_set(m_ghash.size() == GCM_BS);
178 m_ad_len += length;
179 ghash_update(m_ghash, ad, length);
180 }
181
182void GHASH::update(const uint8_t input[], size_t length)
183 {
184 verify_key_set(m_ghash.size() == GCM_BS);
185 m_text_len += length;
186 ghash_update(m_ghash, input, length);
187 }
188
190 size_t ad_len, size_t text_len)
191 {
192 /*
193 * stack buffer is fine here since the text len is public
194 * and the length of the AD is probably not sensitive either.
195 */
196 uint8_t final_block[GCM_BS];
197 store_be<uint64_t>(final_block, 8*ad_len, 8*text_len);
198 ghash_update(hash, final_block, GCM_BS);
199 }
200
201void GHASH::final(uint8_t mac[], size_t mac_len)
202 {
203 BOTAN_ARG_CHECK(mac_len > 0 && mac_len <= 16, "GHASH output length");
204 add_final_block(m_ghash, m_ad_len, m_text_len);
205
206 for(size_t i = 0; i != mac_len; ++i)
207 mac[i] = m_ghash[i] ^ m_nonce[i];
208
209 m_ghash.clear();
210 m_text_len = 0;
211 }
212
213void GHASH::nonce_hash(secure_vector<uint8_t>& y0, const uint8_t nonce[], size_t nonce_len)
214 {
215 BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time");
216
217 ghash_update(y0, nonce, nonce_len);
218 add_final_block(y0, 0, nonce_len);
219 }
220
222 {
223 zap(m_H);
224 zap(m_HM);
225 reset();
226 }
227
229 {
230 zeroise(m_H_ad);
231 m_ghash.clear();
232 m_nonce.clear();
233 m_text_len = m_ad_len = 0;
234 }
235
236}
#define BOTAN_ARG_CHECK(expr, msg)
Definition: assert.h:37
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
static bool has_vperm()
Definition: cpuid.h:362
static bool has_carryless_multiply()
Definition: cpuid.h:395
std::string provider() const
Definition: ghash.cpp:17
secure_vector< uint8_t > final()
Definition: ghash.h:49
secure_vector< uint8_t > nonce_hash(const uint8_t nonce[], size_t nonce_len)
Definition: ghash.h:28
void add_final_block(secure_vector< uint8_t > &x, size_t ad_len, size_t pt_len)
Definition: ghash.cpp:189
void update_associated_data(const uint8_t ad[], size_t len)
Definition: ghash.cpp:175
void clear() override
Definition: ghash.cpp:221
void reset()
Definition: ghash.cpp:228
void start(const uint8_t nonce[], size_t len)
Definition: ghash.cpp:157
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:164
void update(const uint8_t in[], size_t len)
Definition: ghash.cpp:182
void verify_key_set(bool cond) const
Definition: sym_algo.h:171
fe Z
Definition: ge.cpp:29
fe X
Definition: ge.cpp:27
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:59
Definition: alg_id.cpp:13
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:117
void zap(std::vector< T, Alloc > &vec)
Definition: secmem.h:127
void carry(int64_t &h0, int64_t &h1)
void secure_scrub_memory(void *ptr, size_t n)
Definition: os_utils.cpp:66
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:133
uint64_t load_be< uint64_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:217
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
MechanismType hash