/src/botan/src/lib/utils/ghash/ghash.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | namespace Botan { |
17 | | |
18 | 0 | std::string GHASH::provider() const { |
19 | 0 | #if defined(BOTAN_HAS_GHASH_CLMUL_CPU) |
20 | 0 | if(CPUID::has_carryless_multiply()) { |
21 | 0 | return "clmul"; |
22 | 0 | } |
23 | 0 | #endif |
24 | | |
25 | 0 | #if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) |
26 | 0 | if(CPUID::has_vperm()) { |
27 | 0 | return "vperm"; |
28 | 0 | } |
29 | 0 | #endif |
30 | | |
31 | 0 | return "base"; |
32 | 0 | } |
33 | | |
34 | 629 | void GHASH::ghash_multiply(secure_vector<uint8_t>& x, const uint8_t input[], size_t blocks) { |
35 | 629 | #if defined(BOTAN_HAS_GHASH_CLMUL_CPU) |
36 | 629 | if(CPUID::has_carryless_multiply()) { |
37 | 629 | return ghash_multiply_cpu(x.data(), m_H_pow.data(), input, blocks); |
38 | 629 | } |
39 | 0 | #endif |
40 | | |
41 | 0 | #if defined(BOTAN_HAS_GHASH_CLMUL_VPERM) |
42 | 0 | if(CPUID::has_vperm()) { |
43 | 0 | return ghash_multiply_vperm(x.data(), m_HM.data(), input, blocks); |
44 | 0 | } |
45 | 0 | #endif |
46 | | |
47 | 0 | CT::poison(x.data(), x.size()); |
48 | |
|
49 | 0 | const uint64_t ALL_BITS = 0xFFFFFFFFFFFFFFFF; |
50 | |
|
51 | 0 | uint64_t X[2] = {load_be<uint64_t>(x.data(), 0), load_be<uint64_t>(x.data(), 1)}; |
52 | |
|
53 | 0 | for(size_t b = 0; b != blocks; ++b) { |
54 | 0 | X[0] ^= load_be<uint64_t>(input, 2 * b); |
55 | 0 | X[1] ^= load_be<uint64_t>(input, 2 * b + 1); |
56 | |
|
57 | 0 | uint64_t Z[2] = {0, 0}; |
58 | |
|
59 | 0 | for(size_t i = 0; i != 64; ++i) { |
60 | 0 | const uint64_t X0MASK = (ALL_BITS + (X[0] >> 63)) ^ ALL_BITS; |
61 | 0 | const uint64_t X1MASK = (ALL_BITS + (X[1] >> 63)) ^ ALL_BITS; |
62 | |
|
63 | 0 | X[0] <<= 1; |
64 | 0 | X[1] <<= 1; |
65 | |
|
66 | 0 | Z[0] ^= m_HM[4 * i] & X0MASK; |
67 | 0 | Z[1] ^= m_HM[4 * i + 1] & X0MASK; |
68 | 0 | Z[0] ^= m_HM[4 * i + 2] & X1MASK; |
69 | 0 | Z[1] ^= m_HM[4 * i + 3] & X1MASK; |
70 | 0 | } |
71 | |
|
72 | 0 | X[0] = Z[0]; |
73 | 0 | X[1] = Z[1]; |
74 | 0 | } |
75 | |
|
76 | 0 | store_be<uint64_t>(x.data(), X[0], X[1]); |
77 | 0 | CT::unpoison(x.data(), x.size()); |
78 | 0 | } |
79 | | |
80 | 556 | void GHASH::ghash_update(secure_vector<uint8_t>& ghash, const uint8_t input[], size_t length) { |
81 | 556 | assert_key_material_set(!m_H.empty()); |
82 | | |
83 | | /* |
84 | | This assumes if less than block size input then we're just on the |
85 | | final block and should pad with zeros |
86 | | */ |
87 | | |
88 | 556 | const size_t full_blocks = length / GCM_BS; |
89 | 556 | const size_t final_bytes = length - (full_blocks * GCM_BS); |
90 | | |
91 | 556 | if(full_blocks > 0) { |
92 | 325 | ghash_multiply(ghash, input, full_blocks); |
93 | 325 | } |
94 | | |
95 | 556 | if(final_bytes) { |
96 | 304 | uint8_t last_block[GCM_BS] = {0}; |
97 | 304 | copy_mem(last_block, input + full_blocks * GCM_BS, final_bytes); |
98 | 304 | ghash_multiply(ghash, last_block, 1); |
99 | 304 | secure_scrub_memory(last_block, final_bytes); |
100 | 304 | } |
101 | 556 | } |
102 | | |
103 | 369 | bool GHASH::has_keying_material() const { return !m_ghash.empty(); } |
104 | | |
105 | 182 | void GHASH::key_schedule(const uint8_t key[], size_t length) { |
106 | 182 | m_H.assign(key, key + length); |
107 | 182 | m_H_ad.resize(GCM_BS); |
108 | 182 | m_ad_len = 0; |
109 | 182 | m_text_len = 0; |
110 | | |
111 | 182 | uint64_t H0 = load_be<uint64_t>(m_H.data(), 0); |
112 | 182 | uint64_t H1 = load_be<uint64_t>(m_H.data(), 1); |
113 | | |
114 | 182 | const uint64_t R = 0xE100000000000000; |
115 | | |
116 | 182 | m_HM.resize(256); |
117 | | |
118 | | // precompute the multiples of H |
119 | 546 | for(size_t i = 0; i != 2; ++i) { |
120 | 23.6k | for(size_t j = 0; j != 64; ++j) { |
121 | | /* |
122 | | we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68 |
123 | | to make indexing nicer in the multiplication code |
124 | | */ |
125 | 23.2k | m_HM[4 * j + 2 * i] = H0; |
126 | 23.2k | m_HM[4 * j + 2 * i + 1] = H1; |
127 | | |
128 | | // GCM's bit ops are reversed so we carry out of the bottom |
129 | 23.2k | const uint64_t carry = R * (H1 & 1); |
130 | 23.2k | H1 = (H1 >> 1) | (H0 << 63); |
131 | 23.2k | H0 = (H0 >> 1) ^ carry; |
132 | 23.2k | } |
133 | 364 | } |
134 | | |
135 | 182 | #if defined(BOTAN_HAS_GHASH_CLMUL_CPU) |
136 | 182 | if(CPUID::has_carryless_multiply()) { |
137 | 182 | m_H_pow.resize(8); |
138 | 182 | ghash_precompute_cpu(m_H.data(), m_H_pow.data()); |
139 | 182 | } |
140 | 182 | #endif |
141 | 182 | } |
142 | | |
143 | 187 | void GHASH::start(const uint8_t nonce[], size_t len) { |
144 | 187 | BOTAN_ARG_CHECK(len == 16, "GHASH requires a 128-bit nonce"); |
145 | 187 | m_nonce.assign(nonce, nonce + len); |
146 | 187 | m_ghash = m_H_ad; |
147 | 187 | } |
148 | | |
149 | 187 | void GHASH::set_associated_data(const uint8_t input[], size_t length) { |
150 | 187 | if(m_ghash.empty() == false) { |
151 | 0 | throw Invalid_State("Too late to set AD in GHASH"); |
152 | 0 | } |
153 | | |
154 | 187 | zeroise(m_H_ad); |
155 | | |
156 | 187 | ghash_update(m_H_ad, input, length); |
157 | 187 | m_ad_len = length; |
158 | 187 | } |
159 | | |
160 | 0 | void GHASH::update_associated_data(const uint8_t ad[], size_t length) { |
161 | 0 | assert_key_material_set(); |
162 | 0 | m_ad_len += length; |
163 | 0 | ghash_update(m_ghash, ad, length); |
164 | 0 | } |
165 | | |
166 | 182 | void GHASH::update(const uint8_t input[], size_t length) { |
167 | 182 | assert_key_material_set(); |
168 | 182 | m_text_len += length; |
169 | 182 | ghash_update(m_ghash, input, length); |
170 | 182 | } |
171 | | |
172 | 187 | void GHASH::add_final_block(secure_vector<uint8_t>& hash, size_t ad_len, size_t text_len) { |
173 | | /* |
174 | | * stack buffer is fine here since the text len is public |
175 | | * and the length of the AD is probably not sensitive either. |
176 | | */ |
177 | 187 | uint8_t final_block[GCM_BS]; |
178 | 187 | store_be<uint64_t>(final_block, 8 * ad_len, 8 * text_len); |
179 | 187 | ghash_update(hash, final_block, GCM_BS); |
180 | 187 | } |
181 | | |
182 | 187 | void GHASH::final(uint8_t mac[], size_t mac_len) { |
183 | 187 | BOTAN_ARG_CHECK(mac_len > 0 && mac_len <= 16, "GHASH output length"); |
184 | | |
185 | 187 | assert_key_material_set(); |
186 | 187 | add_final_block(m_ghash, m_ad_len, m_text_len); |
187 | | |
188 | 3.17k | for(size_t i = 0; i != mac_len; ++i) { |
189 | 2.99k | mac[i] = m_ghash[i] ^ m_nonce[i]; |
190 | 2.99k | } |
191 | | |
192 | 187 | m_ghash.clear(); |
193 | 187 | m_text_len = 0; |
194 | 187 | } |
195 | | |
196 | 0 | void GHASH::nonce_hash(secure_vector<uint8_t>& y0, const uint8_t nonce[], size_t nonce_len) { |
197 | 0 | BOTAN_ASSERT(m_ghash.empty(), "nonce_hash called during wrong time"); |
198 | |
|
199 | 0 | ghash_update(y0, nonce, nonce_len); |
200 | 0 | add_final_block(y0, 0, nonce_len); |
201 | 0 | } |
202 | | |
203 | 0 | void GHASH::clear() { |
204 | 0 | zap(m_H); |
205 | 0 | zap(m_HM); |
206 | 0 | reset(); |
207 | 0 | } |
208 | | |
209 | 0 | void GHASH::reset() { |
210 | 0 | zeroise(m_H_ad); |
211 | 0 | m_ghash.clear(); |
212 | 0 | m_nonce.clear(); |
213 | 0 | m_text_len = m_ad_len = 0; |
214 | 0 | } |
215 | | |
216 | | } // namespace Botan |