/src/boringssl/crypto/fipsmodule/cipher/internal.h
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H |
16 | | #define OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H |
17 | | |
18 | | #include <openssl/base.h> |
19 | | |
20 | | #include <openssl/aead.h> |
21 | | #include <openssl/aes.h> |
22 | | #include <openssl/span.h> |
23 | | |
24 | | #include "../../internal.h" |
25 | | #include "../../mem_internal.h" |
26 | | #include "../aes/internal.h" |
27 | | |
28 | | #include <algorithm> |
29 | | #include <functional> |
30 | | #include <optional> |
31 | | #include <type_traits> |
32 | | |
33 | | extern "C" { |
34 | | |
35 | | |
36 | | // EVP_CIPH_MODE_MASK contains the bits of `flags` that represent the mode. |
37 | 169k | #define EVP_CIPH_MODE_MASK 0x3f |
38 | | |
39 | | // EVP_AEAD represents a specific AEAD algorithm. |
40 | | struct evp_aead_st { |
41 | | uint8_t key_len; |
42 | | uint8_t nonce_len; |
43 | | uint8_t overhead; |
44 | | uint8_t max_tag_len; |
45 | | |
46 | | // init initialises an `EVP_AEAD_CTX`. If this call returns zero then |
47 | | // `cleanup` will not be called for that context. |
48 | | int (*init)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len, |
49 | | size_t tag_len); |
50 | | int (*init_with_direction)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len, |
51 | | size_t tag_len, enum evp_aead_direction_t dir); |
52 | | void (*cleanup)(EVP_AEAD_CTX *); |
53 | | |
54 | | // AEADs need to provide one of the following sets of methods: |
55 | | // |
56 | | // - openv + sealv: variable tag length AEAD. |
57 | | // - openv_detached + sealv: fixed tag length AEAD. |
58 | | |
59 | | int (*openv)(const EVP_AEAD_CTX *ctx, bssl::Span<const CRYPTO_IOVEC> iovecs, |
60 | | size_t *out_total_bytes, bssl::Span<const uint8_t> nonce, |
61 | | bssl::Span<const CRYPTO_IVEC> aadvecs); |
62 | | |
63 | | int (*sealv)(const EVP_AEAD_CTX *ctx, bssl::Span<const CRYPTO_IOVEC> iovecs, |
64 | | bssl::Span<uint8_t> out_tag, size_t *out_tag_len, |
65 | | bssl::Span<const uint8_t> nonce, |
66 | | bssl::Span<const CRYPTO_IVEC> aadvecs); |
67 | | |
68 | | int (*openv_detached)(const EVP_AEAD_CTX *ctx, |
69 | | bssl::Span<const CRYPTO_IOVEC> iovecs, |
70 | | bssl::Span<const uint8_t> nonce, |
71 | | bssl::Span<const uint8_t> in_tag, |
72 | | bssl::Span<const CRYPTO_IVEC> aadvecs); |
73 | | |
74 | | int (*get_iv)(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, |
75 | | size_t *out_len); |
76 | | |
77 | | size_t (*tag_len)(const EVP_AEAD_CTX *ctx, size_t in_len); |
78 | | }; |
79 | | |
80 | | struct evp_cipher_st { |
81 | | // type contains a NID identifying the cipher. (e.g. NID_aes_128_gcm.) |
82 | | int nid; |
83 | | |
84 | | // block_size contains the block size, in bytes, of the cipher, or 1 for a |
85 | | // stream cipher. |
86 | | unsigned block_size; |
87 | | |
88 | | // key_len contains the key size, in bytes, for the cipher. If the cipher |
89 | | // takes a variable key size then this contains the default size. |
90 | | unsigned key_len; |
91 | | |
92 | | // iv_len contains the IV size, in bytes, or zero if inapplicable. |
93 | | unsigned iv_len; |
94 | | |
95 | | // ctx_size contains the size, in bytes, of the per-key context for this |
96 | | // cipher. |
97 | | unsigned ctx_size; |
98 | | |
99 | | // flags contains the OR of a number of flags. See `EVP_CIPH_*`. |
100 | | uint32_t flags; |
101 | | |
102 | | int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv, |
103 | | int enc); |
104 | | |
105 | | // cipher encrypts/decrypts `in`, write output to `out`. Writes exactly `len` |
106 | | // bytes, which must be a multiple of the `block_size`. |
107 | | // |
108 | | // For ciphers where encryption and decryption operations differ, `init` |
109 | | // shall set an internal state for this. |
110 | | // |
111 | | // Returns 1 on success, or 0 on error. |
112 | | int (*cipher_update)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, |
113 | | size_t len); |
114 | | |
115 | | // cipher_final finalizes the cipher, performing possible final |
116 | | // authentication checks. |
117 | | // |
118 | | // Only used for `EVP_CIPH_FLAG_CUSTOM_CIPHER` ciphers. |
119 | | // |
120 | | // Returns 1 on success, or 0 on error. When decrypting, if an error is |
121 | | // returned, the decrypted data must not be used. |
122 | | int (*cipher_final)(EVP_CIPHER_CTX *ctx); |
123 | | |
124 | | // update_aad adds `in` (of length `inl`) to the authenticated data for the |
125 | | // encryption operation. |
126 | | // |
127 | | // Only used for `EVP_CIPH_FLAG_CUSTOM_CIPHER` ciphers. |
128 | | // |
129 | | // Returns 1 on success, or 0 on error. |
130 | | int (*update_aad)(EVP_CIPHER_CTX *ctx, const uint8_t *in, size_t inl); |
131 | | |
132 | | // cleanup, if non-NULL, releases memory associated with the context. It is |
133 | | // called if `EVP_CTRL_INIT` succeeds. Note that `init` may not have been |
134 | | // called at this point. |
135 | | void (*cleanup)(EVP_CIPHER_CTX *); |
136 | | |
137 | | int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); |
138 | | }; |
139 | | |
140 | | } // extern C |
141 | | |
142 | | BSSL_NAMESPACE_BEGIN |
143 | | |
144 | | // CopySpan copies an entire span of bytes from `from` to `to`. |
145 | | // |
146 | | // The spans need to have the same length. |
147 | 12.3k | inline void CopySpan(Span<const uint8_t> from, Span<uint8_t> to) { |
148 | 12.3k | BSSL_CHECK(from.size() == to.size()); |
149 | 12.3k | std::copy(from.begin(), from.end(), to.begin()); |
150 | 12.3k | } |
151 | | |
152 | | // CopyToPrefix copies a span of bytes from `from` into `to`. It aborts |
153 | | // if there is not enough space. |
154 | | // |
155 | | // TODO(crbug.com/404286922): Can we simplify this in a C++20 world (e.g. |
156 | | // std::ranges::copy)? Must preserve range checking on the destination span. |
157 | 11.0k | inline void CopyToPrefix(Span<const uint8_t> from, Span<uint8_t> to) { |
158 | 11.0k | CopySpan(from, to.first(from.size())); |
159 | 11.0k | } |
160 | | |
161 | | // Generic CRYPTO_IOVEC/CRYPTO_IVEC helpers. |
162 | | namespace iovec { |
163 | | |
164 | | // IsValid returns whether the given `CRYPTO_IVEC` or `CRYPTO_IOVEC` is |
165 | | // valid for use with public APIs, i.e. does not contain more than `SIZE_MAX` |
166 | | // bytes. Note that the `EVP_AEAD` methods need to accept an arbitrary number |
167 | | // of chunks. |
168 | | template <typename IVec> |
169 | 18.9k | inline bool IsValid(Span<IVec> ivecs) { |
170 | 18.9k | size_t allowed = SIZE_MAX; |
171 | 19.6k | for (const IVec &ivec : ivecs) { |
172 | 19.6k | size_t len = ivec.len; |
173 | 19.6k | if (len > allowed) { |
174 | 0 | return false; |
175 | 0 | } |
176 | 19.6k | allowed -= len; |
177 | 19.6k | } |
178 | 18.9k | return true; |
179 | 18.9k | } bool bssl::iovec::IsValid<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>) Line | Count | Source | 169 | 9.49k | inline bool IsValid(Span<IVec> ivecs) { | 170 | 9.49k | size_t allowed = SIZE_MAX; | 171 | 10.1k | for (const IVec &ivec : ivecs) { | 172 | 10.1k | size_t len = ivec.len; | 173 | 10.1k | if (len > allowed) { | 174 | 0 | return false; | 175 | 0 | } | 176 | 10.1k | allowed -= len; | 177 | 10.1k | } | 178 | 9.49k | return true; | 179 | 9.49k | } |
bool bssl::iovec::IsValid<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>) Line | Count | Source | 169 | 9.49k | inline bool IsValid(Span<IVec> ivecs) { | 170 | 9.49k | size_t allowed = SIZE_MAX; | 171 | 9.49k | for (const IVec &ivec : ivecs) { | 172 | 9.49k | size_t len = ivec.len; | 173 | 9.49k | if (len > allowed) { | 174 | 0 | return false; | 175 | 0 | } | 176 | 9.49k | allowed -= len; | 177 | 9.49k | } | 178 | 9.49k | return true; | 179 | 9.49k | } |
|
180 | | |
181 | | // Length returns the total length in bytes of a given `CRYPTO_IVEC` or |
182 | | // `CRYPTO_IOVEC`. |
183 | | template <typename IVec> |
184 | 11.5k | inline size_t TotalLength(Span<IVec> ivecs) { |
185 | 11.5k | size_t total = 0; |
186 | 11.8k | for (const IVec &ivec : ivecs) { |
187 | 11.8k | total += ivec.len; |
188 | 11.8k | } |
189 | 11.5k | return total; |
190 | 11.5k | } unsigned long bssl::iovec::TotalLength<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>) Line | Count | Source | 184 | 6.45k | inline size_t TotalLength(Span<IVec> ivecs) { | 185 | 6.45k | size_t total = 0; | 186 | 6.80k | for (const IVec &ivec : ivecs) { | 187 | 6.80k | total += ivec.len; | 188 | 6.80k | } | 189 | 6.45k | return total; | 190 | 6.45k | } |
unsigned long bssl::iovec::TotalLength<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>) Line | Count | Source | 184 | 5.04k | inline size_t TotalLength(Span<IVec> ivecs) { | 185 | 5.04k | size_t total = 0; | 186 | 5.04k | for (const IVec &ivec : ivecs) { | 187 | 5.04k | total += ivec.len; | 188 | 5.04k | } | 189 | 5.04k | return total; | 190 | 5.04k | } |
Unexecuted instantiation: unsigned long bssl::iovec::TotalLength<crypto_iovec_st>(bssl::Span<crypto_iovec_st, 18446744073709551615ul>) |
191 | | |
192 | | // GetAndRemoveSuffix takes `suffix_buf.size()` final bytes from the given |
193 | | // `CRYPTO_IVEC` or `CRYPTO_IOVEC` (mutating said iovec to no longer contain |
194 | | // those bytes) and returns them. |
195 | | // |
196 | | // If the byte range is contained in a single chunk of `ivecs`, it will just |
197 | | // return that span pointing into `ivecs`; otherwise, it will copy the bytes |
198 | | // into `out` and return that. |
199 | | // |
200 | | // If `ivecs` is too short, returns `nullopt`. |
201 | | template <typename IVec, typename ReadFromT = const uint8_t *, |
202 | | ReadFromT IVec::*ReadFrom = &IVec::in> |
203 | | inline std::optional<Span<const uint8_t>> GetAndRemoveSuffix( |
204 | 3.55k | Span<uint8_t> suffix_buf, Span<IVec> ivecs) { |
205 | | // Get the trivial case out. |
206 | 3.55k | if (suffix_buf.empty()) { |
207 | 0 | return suffix_buf; |
208 | 0 | } |
209 | | // Strip trailing zero length chunks. |
210 | 3.55k | while (!ivecs.empty() && ivecs.back().len == 0) { |
211 | 0 | ivecs = ivecs.first(ivecs.size() - 1); |
212 | 0 | } |
213 | 3.55k | if (ivecs.empty()) { |
214 | 0 | return std::nullopt; |
215 | 0 | } |
216 | | // Is the requested chunk entirely contained? If so, just return it. |
217 | 3.55k | if (ivecs.back().len >= suffix_buf.size()) { |
218 | 3.55k | ivecs.back().len -= suffix_buf.size(); |
219 | 3.55k | return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size()); |
220 | 3.55k | } |
221 | | // Otherwise, collect it into the buffer while trimming `ivecs`. |
222 | 0 | Span<uint8_t> remaining = suffix_buf; |
223 | 0 | while (!ivecs.empty()) { |
224 | 0 | Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len); |
225 | 0 | if (src.size() >= remaining.size()) { |
226 | 0 | CopySpan(src.last(remaining.size()), remaining); |
227 | 0 | ivecs.back().len -= remaining.size(); |
228 | 0 | return suffix_buf; |
229 | 0 | } |
230 | 0 | CopySpan(src, remaining.last(src.size())); |
231 | 0 | remaining = remaining.first(remaining.size() - src.size()); |
232 | 0 | ivecs.back().len = 0; |
233 | 0 | ivecs = ivecs.first(ivecs.size() - 1); |
234 | 0 | } |
235 | 0 | return std::nullopt; |
236 | 0 | } Unexecuted instantiation: _ZN4bssl5iovec18GetAndRemoveSuffixI15crypto_iovec_stPKhTnMT_T0_XadL_ZNS2_2inEEEEENSt3__18optionalINS_4SpanIS3_Lm18446744073709551615EEEEENSA_IhLm18446744073709551615EEENSA_IS5_Lm18446744073709551615EEE _ZN4bssl5iovec18GetAndRemoveSuffixI15crypto_iovec_stPhTnMT_T0_XadL_ZNS2_3outEEEEENSt3__18optionalINS_4SpanIKhLm18446744073709551615EEEEENS9_IhLm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEE Line | Count | Source | 204 | 3.55k | Span<uint8_t> suffix_buf, Span<IVec> ivecs) { | 205 | | // Get the trivial case out. | 206 | 3.55k | if (suffix_buf.empty()) { | 207 | 0 | return suffix_buf; | 208 | 0 | } | 209 | | // Strip trailing zero length chunks. | 210 | 3.55k | while (!ivecs.empty() && ivecs.back().len == 0) { | 211 | 0 | ivecs = ivecs.first(ivecs.size() - 1); | 212 | 0 | } | 213 | 3.55k | if (ivecs.empty()) { | 214 | 0 | return std::nullopt; | 215 | 0 | } | 216 | | // Is the requested chunk entirely contained? If so, just return it. | 217 | 3.55k | if (ivecs.back().len >= suffix_buf.size()) { | 218 | 3.55k | ivecs.back().len -= suffix_buf.size(); | 219 | 3.55k | return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size()); | 220 | 3.55k | } | 221 | | // Otherwise, collect it into the buffer while trimming `ivecs`. | 222 | 0 | Span<uint8_t> remaining = suffix_buf; | 223 | 0 | while (!ivecs.empty()) { | 224 | 0 | Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len); | 225 | 0 | if (src.size() >= remaining.size()) { | 226 | 0 | CopySpan(src.last(remaining.size()), remaining); | 227 | 0 | ivecs.back().len -= remaining.size(); | 228 | 0 | return suffix_buf; | 229 | 0 | } | 230 | 0 | CopySpan(src, remaining.last(src.size())); | 231 | 0 | remaining = remaining.first(remaining.size() - src.size()); | 232 | 0 | ivecs.back().len = 0; | 233 | 0 | ivecs = ivecs.first(ivecs.size() - 1); | 234 | 0 | } | 235 | 0 | return std::nullopt; | 236 | 0 | } |
|
237 | | |
238 | | // GetAndRemoveOutSuffix is like `GetAndRemoveSuffix` but takes from a |
239 | | // `CRYPTO_IOVEC`'s `out` member instead. |
240 | | inline std::optional<Span<const uint8_t>> GetAndRemoveOutSuffix( |
241 | 3.55k | Span<uint8_t> out, Span<CRYPTO_IOVEC> iovecs) { |
242 | 3.55k | return GetAndRemoveSuffix<CRYPTO_IOVEC, /*ReadFromT=*/uint8_t *, |
243 | 3.55k | /*ReadFrom=*/&CRYPTO_IOVEC::out>(out, iovecs); |
244 | 3.55k | } |
245 | | |
246 | | namespace internal { |
247 | | inline void CopySpanToIOVec(Span<const uint8_t> out, CRYPTO_IOVEC head, |
248 | 0 | Span<const CRYPTO_IOVEC> rest) { |
249 | 0 | for (;;) { |
250 | 0 | size_t to_copy = std::min(head.len, out.size()); |
251 | 0 | CopySpan(out.first(to_copy), Span(head.out, to_copy)); |
252 | 0 | out = out.subspan(to_copy); |
253 | 0 | if (out.empty()) { |
254 | 0 | break; |
255 | 0 | } |
256 | 0 | head = rest.front(); // Checkfails if insufficient space in CRYPTO_IOVEC. |
257 | 0 | rest = rest.subspan(1); |
258 | 0 | } |
259 | 0 | } |
260 | | } // namespace internal |
261 | | |
262 | | // ForEachBlockRange iterates over the `ivecs` as follows: |
263 | | // |
264 | | // - `f_whole` gets called on whole blocks crossing `ivecs` chunk boundaries, or |
265 | | // ranges of whole blocks that are entirely in chunks. |
266 | | // - `f` gets called exactly once, on the last block range which may |
267 | | // end up with a partial block. |
268 | | // - Both functions receive an `in` pointer that either points into `ivecs` or |
269 | | // into a chunk assembly buffer and a `len` which indicates the number of |
270 | | // bytes from `in` that can be accessed. If the function returns 0, |
271 | | // iteration stops. |
272 | | // - If `WriteOut` is set, `f_whole` and `f` receive an extra `out` |
273 | | // argument to which they can write output. This output will be placed into |
274 | | // the `ivecs`'s `out` members either during or after the call. If iteration |
275 | | // was stopped, the contents of `out` are indeterminate. |
276 | | // - The return value is true if iteration was not stopped by the callbacks. |
277 | | template < |
278 | | size_t BlockSize, bool WriteOut = false, typename IVec, |
279 | | typename ReadFromT = const uint8_t *, ReadFromT IVec::*ReadFrom = &IVec::in, |
280 | | typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole, |
281 | | typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */ |
282 | | FFinal> |
283 | | inline bool ForEachBlockRange(Span<IVec> ivecs, const FWhole &f_whole, |
284 | 5.04k | const FFinal &f_final) { |
285 | 5.04k | using MutableIVec = std::remove_const_t<IVec>; |
286 | | // Helper to make the function calls simpler. |
287 | 5.04k | auto call_func = [&](const auto &f, const IVec &ivec) { |
288 | 5.04k | if constexpr (WriteOut) { |
289 | 5.04k | return f(ivec.*ReadFrom, ivec.out, ivec.len); |
290 | 5.04k | } else { |
291 | 0 | return f(ivec.*ReadFrom, ivec.len); |
292 | 0 | } |
293 | 5.04k | }; Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISK_EEDaSU_SV_ Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISJ_EEDaST_SU_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISI_EEDaSS_ST_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISH_EEDaSS_ST_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISG_EEDaSQ_SR_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISF_EEDaSQ_SR_ e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISJ_EEDaST_SU_ Line | Count | Source | 287 | 163 | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 163 | if constexpr (WriteOut) { | 289 | 163 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | | } else { | 291 | | return f(ivec.*ReadFrom, ivec.len); | 292 | | } | 293 | 163 | }; |
e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISJ_EEDaST_SU_ Line | Count | Source | 287 | 3.46k | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 3.46k | if constexpr (WriteOut) { | 289 | 3.46k | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | | } else { | 291 | | return f(ivec.*ReadFrom, ivec.len); | 292 | | } | 293 | 3.46k | }; |
e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISL_EEDaSV_SW_ Line | Count | Source | 287 | 654 | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 654 | if constexpr (WriteOut) { | 289 | 654 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | | } else { | 291 | | return f(ivec.*ReadFrom, ivec.len); | 292 | | } | 293 | 654 | }; |
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISK_EEDaSV_SW_ e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISL_EEDaSV_SW_ Line | Count | Source | 287 | 770 | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 770 | if constexpr (WriteOut) { | 289 | 770 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | | } else { | 291 | | return f(ivec.*ReadFrom, ivec.len); | 292 | | } | 293 | 770 | }; |
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISK_EEDaSV_SW_ |
294 | | // Helper to cut from the start of an IVec. |
295 | 5.04k | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { |
296 | 0 | ivec.*ReadFrom += by; |
297 | 0 | if constexpr (WriteOut) { |
298 | 0 | ivec.out += by; |
299 | 0 | } |
300 | 0 | ivec.len -= by; |
301 | 0 | }; Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESS_m Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESR_m Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESQ_m Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESO_m Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESR_m Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESR_m Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clEST_m Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clEST_m |
302 | | // Helper to copy a range to an iovec list. |
303 | 5.04k | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, |
304 | 5.04k | Span<IVec> rest) { |
305 | 0 | if constexpr (WriteOut) { |
306 | 0 | internal::CopySpanToIOVec(out, head, rest); |
307 | 0 | } |
308 | 0 | }; Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlNSH_IS4_Lm18446744073709551615EEES2_SJ_E_clESS_S2_SJ_ Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ENKUlNSG_IKhLm18446744073709551615EEES2_SI_E_clESS_S2_SI_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSD_S2_SA_E_clESD_S2_SA_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSB_S2_SA_E_clESB_S2_SA_ Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSF_S2_SD_E_clESF_S2_SD_ Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSF_S2_SD_E_clESF_S2_SD_ Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSG_S2_SD_E_clESG_S2_SD_ Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSG_S2_SD_E_clESG_S2_SD_ |
309 | | |
310 | | // Ensure the last item in `ivecs` is nonempty. This is necessary for |
311 | | // detecting being at the end and calling `f_final` at the appropriate time. |
312 | 5.04k | Span<IVec> ivecs_trimmed = ivecs; |
313 | 5.04k | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { |
314 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); |
315 | 0 | } |
316 | 5.04k | if (ivecs_trimmed.empty()) { |
317 | 0 | return call_func(f_final, IVec{}); |
318 | 0 | } |
319 | | |
320 | | // Now there are at least two non-empty `ivecs`, and neither the first nor the |
321 | | // last can be empty. |
322 | | |
323 | 5.04k | MutableIVec current_range_head = ivecs_trimmed.front(); |
324 | 5.04k | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); |
325 | 5.04k | while (!current_range_rest.empty()) { |
326 | | // Process as many whole blocks as possible. |
327 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; |
328 | 0 | if (whole_blocks_len != 0) { |
329 | 0 | MutableIVec whole_part = current_range_head; |
330 | 0 | whole_part.len = whole_blocks_len; |
331 | 0 | if (!call_func(f_whole, whole_part)) { |
332 | 0 | return false; |
333 | 0 | } |
334 | 0 | remove_prefix(current_range_head, whole_blocks_len); |
335 | 0 | } |
336 | | |
337 | 0 | if (current_range_head.len == 0) { |
338 | 0 | current_range_head = current_range_rest.front(); |
339 | 0 | current_range_rest = current_range_rest.subspan(1); |
340 | 0 | continue; |
341 | 0 | } |
342 | | |
343 | | // Collect a whole block. |
344 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; |
345 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; |
346 | 0 | MutableIVec collect_from_head = current_range_head; |
347 | 0 | Span<IVec> collect_from_rest = current_range_rest; |
348 | 0 | while (in.size() <= BlockSize) { |
349 | 0 | size_t remaining = BlockSize - in.size(); |
350 | 0 | if (remaining < collect_from_head.len) { |
351 | | // Got enough to complete the block _and more_. |
352 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); |
353 | 0 | remove_prefix(collect_from_head, remaining); |
354 | 0 | break; |
355 | 0 | } |
356 | | // Consume all of `ivec` and advance. |
357 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); |
358 | 0 | if (collect_from_rest.empty()) { |
359 | | // Nothing left - so this is the final block. |
360 | 0 | auto finalout = Span(out).first(in.size()); |
361 | 0 | MutableIVec finalvec = {}; |
362 | 0 | finalvec.len = in.size(); |
363 | 0 | finalvec.*ReadFrom = in.data(); |
364 | 0 | if constexpr (WriteOut) { |
365 | 0 | finalvec.out = finalout.data(); |
366 | 0 | } |
367 | 0 | if (!call_func(f_final, finalvec)) { |
368 | 0 | return false; |
369 | 0 | } |
370 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); |
371 | 0 | return true; |
372 | 0 | } |
373 | 0 | collect_from_head = collect_from_rest.front(); |
374 | 0 | collect_from_rest = collect_from_rest.subspan(1); |
375 | 0 | } |
376 | 0 | assert(in.size() == BlockSize); |
377 | | |
378 | | // The above loop ensures this condition by the `break` only happening if |
379 | | // `collect_from_head` has at least one byte remaining, and the loop |
380 | | // otherwise ensuring as an invariant that the final chunk - which is |
381 | | // nonempty - is among `collect_from_head` and `collect_from_rest`. |
382 | | // |
383 | | // As such, at least one byte is remaining, and thus calling `f_whole` is |
384 | | // appropriate. |
385 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); |
386 | | |
387 | | // Process the block. |
388 | 0 | MutableIVec wholevec = {}; |
389 | 0 | wholevec.len = in.size(); |
390 | 0 | wholevec.*ReadFrom = in.data(); |
391 | 0 | if constexpr (WriteOut) { |
392 | 0 | wholevec.out = out; |
393 | 0 | } |
394 | 0 | if (!call_func(f_whole, wholevec)) { |
395 | 0 | return false; |
396 | 0 | } |
397 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, |
398 | 0 | current_range_rest); |
399 | | |
400 | | // Set the new position. |
401 | 0 | current_range_head = collect_from_head; |
402 | 0 | current_range_rest = collect_from_rest; |
403 | 0 | } |
404 | | |
405 | | // If current_range_head.len is zero, then the last item of ivecs is empty. |
406 | | // That however was excluded at the start of the function to ensure `f_final` |
407 | | // is always used for the last call. |
408 | 5.04k | assert(current_range_head.len != 0); |
409 | | |
410 | 5.04k | return call_func(f_final, current_range_head); |
411 | 5.04k | } Unexecuted instantiation: bcm.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ Unexecuted instantiation: bcm.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ Unexecuted instantiation: e_chacha20poly1305.cc:_ZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ Line | Count | Source | 284 | 163 | const FFinal &f_final) { | 285 | 163 | using MutableIVec = std::remove_const_t<IVec>; | 286 | | // Helper to make the function calls simpler. | 287 | 163 | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 163 | if constexpr (WriteOut) { | 289 | 163 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | 163 | } else { | 291 | 163 | return f(ivec.*ReadFrom, ivec.len); | 292 | 163 | } | 293 | 163 | }; | 294 | | // Helper to cut from the start of an IVec. | 295 | 163 | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 296 | 163 | ivec.*ReadFrom += by; | 297 | 163 | if constexpr (WriteOut) { | 298 | 163 | ivec.out += by; | 299 | 163 | } | 300 | 163 | ivec.len -= by; | 301 | 163 | }; | 302 | | // Helper to copy a range to an iovec list. | 303 | 163 | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 304 | 163 | Span<IVec> rest) { | 305 | 163 | if constexpr (WriteOut) { | 306 | 163 | internal::CopySpanToIOVec(out, head, rest); | 307 | 163 | } | 308 | 163 | }; | 309 | | | 310 | | // Ensure the last item in `ivecs` is nonempty. This is necessary for | 311 | | // detecting being at the end and calling `f_final` at the appropriate time. | 312 | 163 | Span<IVec> ivecs_trimmed = ivecs; | 313 | 163 | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 314 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 315 | 0 | } | 316 | 163 | if (ivecs_trimmed.empty()) { | 317 | 0 | return call_func(f_final, IVec{}); | 318 | 0 | } | 319 | | | 320 | | // Now there are at least two non-empty `ivecs`, and neither the first nor the | 321 | | // last can be empty. | 322 | | | 323 | 163 | MutableIVec current_range_head = ivecs_trimmed.front(); | 324 | 163 | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 325 | 163 | while (!current_range_rest.empty()) { | 326 | | // Process as many whole blocks as possible. | 327 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 328 | 0 | if (whole_blocks_len != 0) { | 329 | 0 | MutableIVec whole_part = current_range_head; | 330 | 0 | whole_part.len = whole_blocks_len; | 331 | 0 | if (!call_func(f_whole, whole_part)) { | 332 | 0 | return false; | 333 | 0 | } | 334 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 335 | 0 | } | 336 | | | 337 | 0 | if (current_range_head.len == 0) { | 338 | 0 | current_range_head = current_range_rest.front(); | 339 | 0 | current_range_rest = current_range_rest.subspan(1); | 340 | 0 | continue; | 341 | 0 | } | 342 | | | 343 | | // Collect a whole block. | 344 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 345 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 346 | 0 | MutableIVec collect_from_head = current_range_head; | 347 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 348 | 0 | while (in.size() <= BlockSize) { | 349 | 0 | size_t remaining = BlockSize - in.size(); | 350 | 0 | if (remaining < collect_from_head.len) { | 351 | | // Got enough to complete the block _and more_. | 352 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 353 | 0 | remove_prefix(collect_from_head, remaining); | 354 | 0 | break; | 355 | 0 | } | 356 | | // Consume all of `ivec` and advance. | 357 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 358 | 0 | if (collect_from_rest.empty()) { | 359 | | // Nothing left - so this is the final block. | 360 | 0 | auto finalout = Span(out).first(in.size()); | 361 | 0 | MutableIVec finalvec = {}; | 362 | 0 | finalvec.len = in.size(); | 363 | 0 | finalvec.*ReadFrom = in.data(); | 364 | 0 | if constexpr (WriteOut) { | 365 | 0 | finalvec.out = finalout.data(); | 366 | 0 | } | 367 | 0 | if (!call_func(f_final, finalvec)) { | 368 | 0 | return false; | 369 | 0 | } | 370 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 371 | 0 | return true; | 372 | 0 | } | 373 | 0 | collect_from_head = collect_from_rest.front(); | 374 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 375 | 0 | } | 376 | 0 | assert(in.size() == BlockSize); | 377 | | | 378 | | // The above loop ensures this condition by the `break` only happening if | 379 | | // `collect_from_head` has at least one byte remaining, and the loop | 380 | | // otherwise ensuring as an invariant that the final chunk - which is | 381 | | // nonempty - is among `collect_from_head` and `collect_from_rest`. | 382 | | // | 383 | | // As such, at least one byte is remaining, and thus calling `f_whole` is | 384 | | // appropriate. | 385 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 386 | | | 387 | | // Process the block. | 388 | 0 | MutableIVec wholevec = {}; | 389 | 0 | wholevec.len = in.size(); | 390 | 0 | wholevec.*ReadFrom = in.data(); | 391 | 0 | if constexpr (WriteOut) { | 392 | 0 | wholevec.out = out; | 393 | 0 | } | 394 | 0 | if (!call_func(f_whole, wholevec)) { | 395 | 0 | return false; | 396 | 0 | } | 397 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 398 | 0 | current_range_rest); | 399 | | | 400 | | // Set the new position. | 401 | 0 | current_range_head = collect_from_head; | 402 | 0 | current_range_rest = collect_from_rest; | 403 | 0 | } | 404 | | | 405 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 406 | | // That however was excluded at the start of the function to ensure `f_final` | 407 | | // is always used for the last call. | 408 | 163 | assert(current_range_head.len != 0); | 409 | | | 410 | 163 | return call_func(f_final, current_range_head); | 411 | 163 | } |
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ Line | Count | Source | 284 | 3.46k | const FFinal &f_final) { | 285 | 3.46k | using MutableIVec = std::remove_const_t<IVec>; | 286 | | // Helper to make the function calls simpler. | 287 | 3.46k | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 3.46k | if constexpr (WriteOut) { | 289 | 3.46k | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | 3.46k | } else { | 291 | 3.46k | return f(ivec.*ReadFrom, ivec.len); | 292 | 3.46k | } | 293 | 3.46k | }; | 294 | | // Helper to cut from the start of an IVec. | 295 | 3.46k | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 296 | 3.46k | ivec.*ReadFrom += by; | 297 | 3.46k | if constexpr (WriteOut) { | 298 | 3.46k | ivec.out += by; | 299 | 3.46k | } | 300 | 3.46k | ivec.len -= by; | 301 | 3.46k | }; | 302 | | // Helper to copy a range to an iovec list. | 303 | 3.46k | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 304 | 3.46k | Span<IVec> rest) { | 305 | 3.46k | if constexpr (WriteOut) { | 306 | 3.46k | internal::CopySpanToIOVec(out, head, rest); | 307 | 3.46k | } | 308 | 3.46k | }; | 309 | | | 310 | | // Ensure the last item in `ivecs` is nonempty. This is necessary for | 311 | | // detecting being at the end and calling `f_final` at the appropriate time. | 312 | 3.46k | Span<IVec> ivecs_trimmed = ivecs; | 313 | 3.46k | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 314 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 315 | 0 | } | 316 | 3.46k | if (ivecs_trimmed.empty()) { | 317 | 0 | return call_func(f_final, IVec{}); | 318 | 0 | } | 319 | | | 320 | | // Now there are at least two non-empty `ivecs`, and neither the first nor the | 321 | | // last can be empty. | 322 | | | 323 | 3.46k | MutableIVec current_range_head = ivecs_trimmed.front(); | 324 | 3.46k | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 325 | 3.46k | while (!current_range_rest.empty()) { | 326 | | // Process as many whole blocks as possible. | 327 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 328 | 0 | if (whole_blocks_len != 0) { | 329 | 0 | MutableIVec whole_part = current_range_head; | 330 | 0 | whole_part.len = whole_blocks_len; | 331 | 0 | if (!call_func(f_whole, whole_part)) { | 332 | 0 | return false; | 333 | 0 | } | 334 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 335 | 0 | } | 336 | | | 337 | 0 | if (current_range_head.len == 0) { | 338 | 0 | current_range_head = current_range_rest.front(); | 339 | 0 | current_range_rest = current_range_rest.subspan(1); | 340 | 0 | continue; | 341 | 0 | } | 342 | | | 343 | | // Collect a whole block. | 344 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 345 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 346 | 0 | MutableIVec collect_from_head = current_range_head; | 347 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 348 | 0 | while (in.size() <= BlockSize) { | 349 | 0 | size_t remaining = BlockSize - in.size(); | 350 | 0 | if (remaining < collect_from_head.len) { | 351 | | // Got enough to complete the block _and more_. | 352 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 353 | 0 | remove_prefix(collect_from_head, remaining); | 354 | 0 | break; | 355 | 0 | } | 356 | | // Consume all of `ivec` and advance. | 357 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 358 | 0 | if (collect_from_rest.empty()) { | 359 | | // Nothing left - so this is the final block. | 360 | 0 | auto finalout = Span(out).first(in.size()); | 361 | 0 | MutableIVec finalvec = {}; | 362 | 0 | finalvec.len = in.size(); | 363 | 0 | finalvec.*ReadFrom = in.data(); | 364 | 0 | if constexpr (WriteOut) { | 365 | 0 | finalvec.out = finalout.data(); | 366 | 0 | } | 367 | 0 | if (!call_func(f_final, finalvec)) { | 368 | 0 | return false; | 369 | 0 | } | 370 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 371 | 0 | return true; | 372 | 0 | } | 373 | 0 | collect_from_head = collect_from_rest.front(); | 374 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 375 | 0 | } | 376 | 0 | assert(in.size() == BlockSize); | 377 | | | 378 | | // The above loop ensures this condition by the `break` only happening if | 379 | | // `collect_from_head` has at least one byte remaining, and the loop | 380 | | // otherwise ensuring as an invariant that the final chunk - which is | 381 | | // nonempty - is among `collect_from_head` and `collect_from_rest`. | 382 | | // | 383 | | // As such, at least one byte is remaining, and thus calling `f_whole` is | 384 | | // appropriate. | 385 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 386 | | | 387 | | // Process the block. | 388 | 0 | MutableIVec wholevec = {}; | 389 | 0 | wholevec.len = in.size(); | 390 | 0 | wholevec.*ReadFrom = in.data(); | 391 | 0 | if constexpr (WriteOut) { | 392 | 0 | wholevec.out = out; | 393 | 0 | } | 394 | 0 | if (!call_func(f_whole, wholevec)) { | 395 | 0 | return false; | 396 | 0 | } | 397 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 398 | 0 | current_range_rest); | 399 | | | 400 | | // Set the new position. | 401 | 0 | current_range_head = collect_from_head; | 402 | 0 | current_range_rest = collect_from_rest; | 403 | 0 | } | 404 | | | 405 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 406 | | // That however was excluded at the start of the function to ensure `f_final` | 407 | | // is always used for the last call. | 408 | 3.46k | assert(current_range_head.len != 0); | 409 | | | 410 | 3.46k | return call_func(f_final, current_range_head); | 411 | 3.46k | } |
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ Line | Count | Source | 284 | 654 | const FFinal &f_final) { | 285 | 654 | using MutableIVec = std::remove_const_t<IVec>; | 286 | | // Helper to make the function calls simpler. | 287 | 654 | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 654 | if constexpr (WriteOut) { | 289 | 654 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | 654 | } else { | 291 | 654 | return f(ivec.*ReadFrom, ivec.len); | 292 | 654 | } | 293 | 654 | }; | 294 | | // Helper to cut from the start of an IVec. | 295 | 654 | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 296 | 654 | ivec.*ReadFrom += by; | 297 | 654 | if constexpr (WriteOut) { | 298 | 654 | ivec.out += by; | 299 | 654 | } | 300 | 654 | ivec.len -= by; | 301 | 654 | }; | 302 | | // Helper to copy a range to an iovec list. | 303 | 654 | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 304 | 654 | Span<IVec> rest) { | 305 | 654 | if constexpr (WriteOut) { | 306 | 654 | internal::CopySpanToIOVec(out, head, rest); | 307 | 654 | } | 308 | 654 | }; | 309 | | | 310 | | // Ensure the last item in `ivecs` is nonempty. This is necessary for | 311 | | // detecting being at the end and calling `f_final` at the appropriate time. | 312 | 654 | Span<IVec> ivecs_trimmed = ivecs; | 313 | 654 | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 314 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 315 | 0 | } | 316 | 654 | if (ivecs_trimmed.empty()) { | 317 | 0 | return call_func(f_final, IVec{}); | 318 | 0 | } | 319 | | | 320 | | // Now there are at least two non-empty `ivecs`, and neither the first nor the | 321 | | // last can be empty. | 322 | | | 323 | 654 | MutableIVec current_range_head = ivecs_trimmed.front(); | 324 | 654 | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 325 | 654 | while (!current_range_rest.empty()) { | 326 | | // Process as many whole blocks as possible. | 327 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 328 | 0 | if (whole_blocks_len != 0) { | 329 | 0 | MutableIVec whole_part = current_range_head; | 330 | 0 | whole_part.len = whole_blocks_len; | 331 | 0 | if (!call_func(f_whole, whole_part)) { | 332 | 0 | return false; | 333 | 0 | } | 334 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 335 | 0 | } | 336 | | | 337 | 0 | if (current_range_head.len == 0) { | 338 | 0 | current_range_head = current_range_rest.front(); | 339 | 0 | current_range_rest = current_range_rest.subspan(1); | 340 | 0 | continue; | 341 | 0 | } | 342 | | | 343 | | // Collect a whole block. | 344 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 345 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 346 | 0 | MutableIVec collect_from_head = current_range_head; | 347 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 348 | 0 | while (in.size() <= BlockSize) { | 349 | 0 | size_t remaining = BlockSize - in.size(); | 350 | 0 | if (remaining < collect_from_head.len) { | 351 | | // Got enough to complete the block _and more_. | 352 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 353 | 0 | remove_prefix(collect_from_head, remaining); | 354 | 0 | break; | 355 | 0 | } | 356 | | // Consume all of `ivec` and advance. | 357 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 358 | 0 | if (collect_from_rest.empty()) { | 359 | | // Nothing left - so this is the final block. | 360 | 0 | auto finalout = Span(out).first(in.size()); | 361 | 0 | MutableIVec finalvec = {}; | 362 | 0 | finalvec.len = in.size(); | 363 | 0 | finalvec.*ReadFrom = in.data(); | 364 | 0 | if constexpr (WriteOut) { | 365 | 0 | finalvec.out = finalout.data(); | 366 | 0 | } | 367 | 0 | if (!call_func(f_final, finalvec)) { | 368 | 0 | return false; | 369 | 0 | } | 370 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 371 | 0 | return true; | 372 | 0 | } | 373 | 0 | collect_from_head = collect_from_rest.front(); | 374 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 375 | 0 | } | 376 | 0 | assert(in.size() == BlockSize); | 377 | | | 378 | | // The above loop ensures this condition by the `break` only happening if | 379 | | // `collect_from_head` has at least one byte remaining, and the loop | 380 | | // otherwise ensuring as an invariant that the final chunk - which is | 381 | | // nonempty - is among `collect_from_head` and `collect_from_rest`. | 382 | | // | 383 | | // As such, at least one byte is remaining, and thus calling `f_whole` is | 384 | | // appropriate. | 385 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 386 | | | 387 | | // Process the block. | 388 | 0 | MutableIVec wholevec = {}; | 389 | 0 | wholevec.len = in.size(); | 390 | 0 | wholevec.*ReadFrom = in.data(); | 391 | 0 | if constexpr (WriteOut) { | 392 | 0 | wholevec.out = out; | 393 | 0 | } | 394 | 0 | if (!call_func(f_whole, wholevec)) { | 395 | 0 | return false; | 396 | 0 | } | 397 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 398 | 0 | current_range_rest); | 399 | | | 400 | | // Set the new position. | 401 | 0 | current_range_head = collect_from_head; | 402 | 0 | current_range_rest = collect_from_rest; | 403 | 0 | } | 404 | | | 405 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 406 | | // That however was excluded at the start of the function to ensure `f_final` | 407 | | // is always used for the last call. | 408 | 654 | assert(current_range_head.len != 0); | 409 | | | 410 | 654 | return call_func(f_final, current_range_head); | 411 | 654 | } |
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ Line | Count | Source | 284 | 770 | const FFinal &f_final) { | 285 | 770 | using MutableIVec = std::remove_const_t<IVec>; | 286 | | // Helper to make the function calls simpler. | 287 | 770 | auto call_func = [&](const auto &f, const IVec &ivec) { | 288 | 770 | if constexpr (WriteOut) { | 289 | 770 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 290 | 770 | } else { | 291 | 770 | return f(ivec.*ReadFrom, ivec.len); | 292 | 770 | } | 293 | 770 | }; | 294 | | // Helper to cut from the start of an IVec. | 295 | 770 | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 296 | 770 | ivec.*ReadFrom += by; | 297 | 770 | if constexpr (WriteOut) { | 298 | 770 | ivec.out += by; | 299 | 770 | } | 300 | 770 | ivec.len -= by; | 301 | 770 | }; | 302 | | // Helper to copy a range to an iovec list. | 303 | 770 | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 304 | 770 | Span<IVec> rest) { | 305 | 770 | if constexpr (WriteOut) { | 306 | 770 | internal::CopySpanToIOVec(out, head, rest); | 307 | 770 | } | 308 | 770 | }; | 309 | | | 310 | | // Ensure the last item in `ivecs` is nonempty. This is necessary for | 311 | | // detecting being at the end and calling `f_final` at the appropriate time. | 312 | 770 | Span<IVec> ivecs_trimmed = ivecs; | 313 | 770 | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 314 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 315 | 0 | } | 316 | 770 | if (ivecs_trimmed.empty()) { | 317 | 0 | return call_func(f_final, IVec{}); | 318 | 0 | } | 319 | | | 320 | | // Now there are at least two non-empty `ivecs`, and neither the first nor the | 321 | | // last can be empty. | 322 | | | 323 | 770 | MutableIVec current_range_head = ivecs_trimmed.front(); | 324 | 770 | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 325 | 770 | while (!current_range_rest.empty()) { | 326 | | // Process as many whole blocks as possible. | 327 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 328 | 0 | if (whole_blocks_len != 0) { | 329 | 0 | MutableIVec whole_part = current_range_head; | 330 | 0 | whole_part.len = whole_blocks_len; | 331 | 0 | if (!call_func(f_whole, whole_part)) { | 332 | 0 | return false; | 333 | 0 | } | 334 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 335 | 0 | } | 336 | | | 337 | 0 | if (current_range_head.len == 0) { | 338 | 0 | current_range_head = current_range_rest.front(); | 339 | 0 | current_range_rest = current_range_rest.subspan(1); | 340 | 0 | continue; | 341 | 0 | } | 342 | | | 343 | | // Collect a whole block. | 344 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 345 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 346 | 0 | MutableIVec collect_from_head = current_range_head; | 347 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 348 | 0 | while (in.size() <= BlockSize) { | 349 | 0 | size_t remaining = BlockSize - in.size(); | 350 | 0 | if (remaining < collect_from_head.len) { | 351 | | // Got enough to complete the block _and more_. | 352 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 353 | 0 | remove_prefix(collect_from_head, remaining); | 354 | 0 | break; | 355 | 0 | } | 356 | | // Consume all of `ivec` and advance. | 357 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 358 | 0 | if (collect_from_rest.empty()) { | 359 | | // Nothing left - so this is the final block. | 360 | 0 | auto finalout = Span(out).first(in.size()); | 361 | 0 | MutableIVec finalvec = {}; | 362 | 0 | finalvec.len = in.size(); | 363 | 0 | finalvec.*ReadFrom = in.data(); | 364 | 0 | if constexpr (WriteOut) { | 365 | 0 | finalvec.out = finalout.data(); | 366 | 0 | } | 367 | 0 | if (!call_func(f_final, finalvec)) { | 368 | 0 | return false; | 369 | 0 | } | 370 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 371 | 0 | return true; | 372 | 0 | } | 373 | 0 | collect_from_head = collect_from_rest.front(); | 374 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 375 | 0 | } | 376 | 0 | assert(in.size() == BlockSize); | 377 | | | 378 | | // The above loop ensures this condition by the `break` only happening if | 379 | | // `collect_from_head` has at least one byte remaining, and the loop | 380 | | // otherwise ensuring as an invariant that the final chunk - which is | 381 | | // nonempty - is among `collect_from_head` and `collect_from_rest`. | 382 | | // | 383 | | // As such, at least one byte is remaining, and thus calling `f_whole` is | 384 | | // appropriate. | 385 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 386 | | | 387 | | // Process the block. | 388 | 0 | MutableIVec wholevec = {}; | 389 | 0 | wholevec.len = in.size(); | 390 | 0 | wholevec.*ReadFrom = in.data(); | 391 | 0 | if constexpr (WriteOut) { | 392 | 0 | wholevec.out = out; | 393 | 0 | } | 394 | 0 | if (!call_func(f_whole, wholevec)) { | 395 | 0 | return false; | 396 | 0 | } | 397 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 398 | 0 | current_range_rest); | 399 | | | 400 | | // Set the new position. | 401 | 0 | current_range_head = collect_from_head; | 402 | 0 | current_range_rest = collect_from_rest; | 403 | 0 | } | 404 | | | 405 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 406 | | // That however was excluded at the start of the function to ensure `f_final` | 407 | | // is always used for the last call. | 408 | 770 | assert(current_range_head.len != 0); | 409 | | | 410 | 770 | return call_func(f_final, current_range_head); | 411 | 770 | } |
|
412 | | |
413 | | // MaybeInplaceArray can hold a copy of a CRYPTO_IOVEC. If it is a low |
414 | | // amount of entries, it will be stored on the stack, otherwise on the heap. |
415 | | using MaybeInplaceArray = bssl::MaybeInplaceArray<CRYPTO_IOVEC, 16>; |
416 | | |
417 | | // ForEachOutBlockRange is like `ForEachBlockRange` but reads from a |
418 | | // `CRYPTO_IOVEC`'s `out` member instead. |
419 | | template < |
420 | | size_t BlockSize, |
421 | | typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole, |
422 | | typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */ |
423 | | FFinal> |
424 | | inline int ForEachOutBlockRange(Span<const CRYPTO_IOVEC> iovecs, |
425 | 0 | const FWhole &f_whole, const FFinal &f_final) { |
426 | 0 | return ForEachBlockRange<BlockSize, /*WriteOut=*/false, const CRYPTO_IOVEC, |
427 | 0 | /*ReadFromT=*/uint8_t *, |
428 | 0 | /*ReadFrom=*/&CRYPTO_IOVEC::out>(iovecs, f_whole, |
429 | 0 | f_final); |
430 | 0 | } |
431 | | |
432 | | // ForEachBlockRange_Dynamic is simply `ForEachBlockRange` with a |
433 | | // runtime dispatch on the block size. |
434 | | template < |
435 | | bool WriteOut = false, typename IVec, typename ReadFromT = const uint8_t *, |
436 | | ReadFromT IVec::*ReadFrom = &IVec::in, |
437 | | typename /* int(const uint8_t *in, uint8_t *out, size_t len) */ FWhole, |
438 | | typename /* int(const uint8_t *in, uint8_t *out, size_t len) */ |
439 | | FFinal> |
440 | | inline int ForEachBlockRange_Dynamic(size_t block_size, Span<IVec> ivecs, |
441 | | const FWhole &f_whole, |
442 | 5.04k | const FFinal &f_final) { |
443 | 5.04k | switch (block_size) { |
444 | 817 | case 8: |
445 | 817 | return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>( |
446 | 817 | ivecs, f_whole, f_final); |
447 | 0 | break; |
448 | 4.23k | case 16: |
449 | 4.23k | return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>( |
450 | 4.23k | ivecs, f_whole, f_final); |
451 | 0 | break; |
452 | 0 | default: |
453 | 0 | return 0; |
454 | 5.04k | } |
455 | 5.04k | } e_tls.cc:_ZN4bssl5iovec25ForEachBlockRange_DynamicILb1EK15crypto_iovec_stPKhTnMT0_T1_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEimNSC_IS6_Lm18446744073709551615EEERKT3_RKT4_ Line | Count | Source | 442 | 3.62k | const FFinal &f_final) { | 443 | 3.62k | switch (block_size) { | 444 | 163 | case 8: | 445 | 163 | return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>( | 446 | 163 | ivecs, f_whole, f_final); | 447 | 0 | break; | 448 | 3.46k | case 16: | 449 | 3.46k | return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>( | 450 | 3.46k | ivecs, f_whole, f_final); | 451 | 0 | break; | 452 | 0 | default: | 453 | 0 | return 0; | 454 | 3.62k | } | 455 | 3.62k | } |
e_tls.cc:_ZN4bssl5iovec25ForEachBlockRange_DynamicILb1EK15crypto_iovec_stPKhTnMT0_T1_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEimNSC_IS6_Lm18446744073709551615EEERKT3_RKT4_ Line | Count | Source | 442 | 1.42k | const FFinal &f_final) { | 443 | 1.42k | switch (block_size) { | 444 | 654 | case 8: | 445 | 654 | return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>( | 446 | 654 | ivecs, f_whole, f_final); | 447 | 0 | break; | 448 | 770 | case 16: | 449 | 770 | return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>( | 450 | 770 | ivecs, f_whole, f_final); | 451 | 0 | break; | 452 | 0 | default: | 453 | 0 | return 0; | 454 | 1.42k | } | 455 | 1.42k | } |
|
456 | | |
457 | | } // namespace iovec |
458 | | |
459 | | BSSL_NAMESPACE_END |
460 | | |
461 | | #endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H |