Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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