/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 | 182k | #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 lenght 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.8k | inline void CopySpan(Span<const uint8_t> from, Span<uint8_t> to) { |
148 | 12.8k | BSSL_CHECK(from.size() == to.size()); |
149 | 12.8k | std::copy(from.begin(), from.end(), to.begin()); |
150 | 12.8k | } |
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 | 10.9k | inline void CopyToPrefix(Span<const uint8_t> from, Span<uint8_t> to) { |
158 | 10.9k | CopySpan(from, to.first(from.size())); |
159 | 10.9k | } |
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 and not more than |CRYPTO_IOVEC_MAX| chunks. Note that the `EVP_AEAD` |
167 | | // methods need to accept an arbitrary number of chunks. |
168 | | template <typename IVec> |
169 | 20.8k | inline bool IsValid(Span<IVec> ivecs) { |
170 | 20.8k | if (ivecs.size() > CRYPTO_IOVEC_MAX) { |
171 | 0 | return false; |
172 | 0 | } |
173 | 20.8k | size_t allowed = SIZE_MAX; |
174 | 21.4k | for (const IVec &ivec : ivecs) { |
175 | 21.4k | size_t len = ivec.len; |
176 | 21.4k | if (len > allowed) { |
177 | 0 | return false; |
178 | 0 | } |
179 | 21.4k | allowed -= len; |
180 | 21.4k | } |
181 | 20.8k | return true; |
182 | 20.8k | } bool bssl::iovec::IsValid<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>) Line | Count | Source | 169 | 10.4k | inline bool IsValid(Span<IVec> ivecs) { | 170 | 10.4k | if (ivecs.size() > CRYPTO_IOVEC_MAX) { | 171 | 0 | return false; | 172 | 0 | } | 173 | 10.4k | size_t allowed = SIZE_MAX; | 174 | 11.0k | for (const IVec &ivec : ivecs) { | 175 | 11.0k | size_t len = ivec.len; | 176 | 11.0k | if (len > allowed) { | 177 | 0 | return false; | 178 | 0 | } | 179 | 11.0k | allowed -= len; | 180 | 11.0k | } | 181 | 10.4k | return true; | 182 | 10.4k | } |
bool bssl::iovec::IsValid<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>) Line | Count | Source | 169 | 10.4k | inline bool IsValid(Span<IVec> ivecs) { | 170 | 10.4k | if (ivecs.size() > CRYPTO_IOVEC_MAX) { | 171 | 0 | return false; | 172 | 0 | } | 173 | 10.4k | size_t allowed = SIZE_MAX; | 174 | 10.4k | for (const IVec &ivec : ivecs) { | 175 | 10.4k | size_t len = ivec.len; | 176 | 10.4k | if (len > allowed) { | 177 | 0 | return false; | 178 | 0 | } | 179 | 10.4k | allowed -= len; | 180 | 10.4k | } | 181 | 10.4k | return true; | 182 | 10.4k | } |
|
183 | | |
184 | | // Length returns the total length in bytes of a given |CRYPTO_IVEC| or |
185 | | // |CRYPTO_IOVEC|. |
186 | | template <typename IVec> |
187 | 12.8k | inline size_t TotalLength(Span<IVec> ivecs) { |
188 | 12.8k | size_t total = 0; |
189 | 13.0k | for (const IVec &ivec : ivecs) { |
190 | 13.0k | total += ivec.len; |
191 | 13.0k | } |
192 | 12.8k | return total; |
193 | 12.8k | } unsigned long bssl::iovec::TotalLength<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>) Line | Count | Source | 187 | 7.41k | inline size_t TotalLength(Span<IVec> ivecs) { | 188 | 7.41k | size_t total = 0; | 189 | 7.66k | for (const IVec &ivec : ivecs) { | 190 | 7.66k | total += ivec.len; | 191 | 7.66k | } | 192 | 7.41k | return total; | 193 | 7.41k | } |
unsigned long bssl::iovec::TotalLength<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>) Line | Count | Source | 187 | 5.40k | inline size_t TotalLength(Span<IVec> ivecs) { | 188 | 5.40k | size_t total = 0; | 189 | 5.40k | for (const IVec &ivec : ivecs) { | 190 | 5.40k | total += ivec.len; | 191 | 5.40k | } | 192 | 5.40k | return total; | 193 | 5.40k | } |
Unexecuted instantiation: unsigned long bssl::iovec::TotalLength<crypto_iovec_st>(bssl::Span<crypto_iovec_st, 18446744073709551615ul>) |
194 | | |
195 | | // GetAndRemoveSuffix takes |suffix_buf.size()| final bytes from the given |
196 | | // |CRYPTO_IVEC| or |CRYPTO_IOVEC| (mutating said iovec to no longer contain |
197 | | // those bytes) and returns them. |
198 | | // |
199 | | // If the byte range is contained in a single chunk of |ivecs|, it will just |
200 | | // return that span pointing into |ivecs|; otherwise, it will copy the bytes |
201 | | // into |out| and return that. |
202 | | // |
203 | | // If |ivecs| is too short, returns |nullopt|. |
204 | | template <typename IVec, typename ReadFromT = const uint8_t *, |
205 | | ReadFromT IVec::*ReadFrom = &IVec::in> |
206 | | inline std::optional<Span<const uint8_t>> GetAndRemoveSuffix( |
207 | 3.99k | Span<uint8_t> suffix_buf, Span<IVec> ivecs) { |
208 | | // Get the trivial case out. |
209 | 3.99k | if (suffix_buf.empty()) { |
210 | 0 | return suffix_buf; |
211 | 0 | } |
212 | | // Strip trailing zero length chunks. |
213 | 3.99k | while (!ivecs.empty() && ivecs.back().len == 0) { |
214 | 0 | ivecs = ivecs.first(ivecs.size() - 1); |
215 | 0 | } |
216 | 3.99k | if (ivecs.empty()) { |
217 | 0 | return std::nullopt; |
218 | 0 | } |
219 | | // Is the requested chunk entirely contained? If so, just return it. |
220 | 3.99k | if (ivecs.back().len >= suffix_buf.size()) { |
221 | 3.99k | ivecs.back().len -= suffix_buf.size(); |
222 | 3.99k | return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size()); |
223 | 3.99k | } |
224 | | // Otherwise, collect it into the buffer while trimming |ivecs|. |
225 | 0 | Span<uint8_t> remaining = suffix_buf; |
226 | 0 | while (!ivecs.empty()) { |
227 | 0 | Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len); |
228 | 0 | if (src.size() >= remaining.size()) { |
229 | 0 | CopySpan(src.last(remaining.size()), remaining); |
230 | 0 | ivecs.back().len -= remaining.size(); |
231 | 0 | return suffix_buf; |
232 | 0 | } |
233 | 0 | CopySpan(src, remaining.last(src.size())); |
234 | 0 | remaining = remaining.first(remaining.size() - src.size()); |
235 | 0 | ivecs.back().len = 0; |
236 | 0 | ivecs = ivecs.first(ivecs.size() - 1); |
237 | 0 | } |
238 | 0 | return std::nullopt; |
239 | 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 | 207 | 3.99k | Span<uint8_t> suffix_buf, Span<IVec> ivecs) { | 208 | | // Get the trivial case out. | 209 | 3.99k | if (suffix_buf.empty()) { | 210 | 0 | return suffix_buf; | 211 | 0 | } | 212 | | // Strip trailing zero length chunks. | 213 | 3.99k | while (!ivecs.empty() && ivecs.back().len == 0) { | 214 | 0 | ivecs = ivecs.first(ivecs.size() - 1); | 215 | 0 | } | 216 | 3.99k | if (ivecs.empty()) { | 217 | 0 | return std::nullopt; | 218 | 0 | } | 219 | | // Is the requested chunk entirely contained? If so, just return it. | 220 | 3.99k | if (ivecs.back().len >= suffix_buf.size()) { | 221 | 3.99k | ivecs.back().len -= suffix_buf.size(); | 222 | 3.99k | return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size()); | 223 | 3.99k | } | 224 | | // Otherwise, collect it into the buffer while trimming |ivecs|. | 225 | 0 | Span<uint8_t> remaining = suffix_buf; | 226 | 0 | while (!ivecs.empty()) { | 227 | 0 | Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len); | 228 | 0 | if (src.size() >= remaining.size()) { | 229 | 0 | CopySpan(src.last(remaining.size()), remaining); | 230 | 0 | ivecs.back().len -= remaining.size(); | 231 | 0 | return suffix_buf; | 232 | 0 | } | 233 | 0 | CopySpan(src, remaining.last(src.size())); | 234 | 0 | remaining = remaining.first(remaining.size() - src.size()); | 235 | 0 | ivecs.back().len = 0; | 236 | 0 | ivecs = ivecs.first(ivecs.size() - 1); | 237 | 0 | } | 238 | 0 | return std::nullopt; | 239 | 0 | } |
|
240 | | |
241 | | // GetAndRemoveOutSuffix is like |GetAndRemoveSuffix| but takes from a |
242 | | // |CRYPTO_IOVEC|'s |out| member instead. |
243 | | inline std::optional<Span<const uint8_t>> GetAndRemoveOutSuffix( |
244 | 3.99k | Span<uint8_t> out, Span<CRYPTO_IOVEC> iovecs) { |
245 | 3.99k | return GetAndRemoveSuffix<CRYPTO_IOVEC, /*ReadFromT=*/uint8_t *, |
246 | 3.99k | /*ReadFrom=*/&CRYPTO_IOVEC::out>(out, iovecs); |
247 | 3.99k | } |
248 | | |
249 | | namespace internal { |
250 | | inline void CopySpanToIOVec(Span<const uint8_t> out, CRYPTO_IOVEC head, |
251 | 0 | Span<const CRYPTO_IOVEC> rest) { |
252 | 0 | for (;;) { |
253 | 0 | size_t to_copy = std::min(head.len, out.size()); |
254 | 0 | CopySpan(out.first(to_copy), Span(head.out, to_copy)); |
255 | 0 | out = out.subspan(to_copy); |
256 | 0 | if (out.empty()) { |
257 | 0 | break; |
258 | 0 | } |
259 | 0 | head = rest.front(); // Checkfails if insufficient space in CRYPTO_IOVEC. |
260 | 0 | rest = rest.subspan(1); |
261 | 0 | } |
262 | 0 | } |
263 | | } // namespace internal |
264 | | |
265 | | // ForEachBlockRange iterates over the |ivecs| as follows: |
266 | | // |
267 | | // - |f_whole| gets called on whole blocks crossing |ivecs| chunk boundaries, or |
268 | | // ranges of whole blocks that are entirely in chunks. |
269 | | // - |f| gets called exactly once, on the last block range which may |
270 | | // end up with a partial block. |
271 | | // - Both functions receive an |in| pointer that either points into |ivecs| or |
272 | | // into a chunk assembly buffer and a |len| which indicates the number of |
273 | | // bytes from |in| that can be accessed. If the function returns 0, |
274 | | // iteration stops. |
275 | | // - If |WriteOut| is set, |f_whole| and |f| receive an extra |out| |
276 | | // argument to which they can write output. This output will be placed into |
277 | | // the |ivecs|'s |out| members either during or after the call. If iteration |
278 | | // was stopped, the contents of |out| are indeterminate. |
279 | | // - The return value is true if iteration was not stopped by the callbacks. |
280 | | template < |
281 | | size_t BlockSize, bool WriteOut = false, typename IVec, |
282 | | typename ReadFromT = const uint8_t *, ReadFromT IVec::*ReadFrom = &IVec::in, |
283 | | typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole, |
284 | | typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */ |
285 | | FFinal> |
286 | | inline bool ForEachBlockRange(Span<IVec> ivecs, const FWhole &f_whole, |
287 | 5.40k | const FFinal &f_final) { |
288 | 5.40k | using MutableIVec = std::remove_const_t<IVec>; |
289 | | // Helper to make the function calls simpler. |
290 | 5.40k | auto call_func = [&](const auto &f, const IVec &ivec) { |
291 | 5.40k | if constexpr (WriteOut) { |
292 | 5.40k | return f(ivec.*ReadFrom, ivec.out, ivec.len); |
293 | 5.40k | } else { |
294 | 0 | return f(ivec.*ReadFrom, ivec.len); |
295 | 0 | } |
296 | 5.40k | }; 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 | 290 | 137 | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 137 | if constexpr (WriteOut) { | 292 | 137 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | | } else { | 294 | | return f(ivec.*ReadFrom, ivec.len); | 295 | | } | 296 | 137 | }; |
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 | 290 | 3.93k | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 3.93k | if constexpr (WriteOut) { | 292 | 3.93k | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | | } else { | 294 | | return f(ivec.*ReadFrom, ivec.len); | 295 | | } | 296 | 3.93k | }; |
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 | 290 | 626 | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 626 | if constexpr (WriteOut) { | 292 | 626 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | | } else { | 294 | | return f(ivec.*ReadFrom, ivec.len); | 295 | | } | 296 | 626 | }; |
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 | 290 | 714 | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 714 | if constexpr (WriteOut) { | 292 | 714 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | | } else { | 294 | | return f(ivec.*ReadFrom, ivec.len); | 295 | | } | 296 | 714 | }; |
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_ |
297 | | // Helper to cut from the start of an IVec. |
298 | 5.40k | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { |
299 | 0 | ivec.*ReadFrom += by; |
300 | 0 | if constexpr (WriteOut) { |
301 | 0 | ivec.out += by; |
302 | 0 | } |
303 | 0 | ivec.len -= by; |
304 | 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 |
305 | | // Helper to copy a range to an iovec list. |
306 | 5.40k | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, |
307 | 5.40k | Span<IVec> rest) { |
308 | 0 | if constexpr (WriteOut) { |
309 | 0 | internal::CopySpanToIOVec(out, head, rest); |
310 | 0 | } |
311 | 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_ |
312 | | |
313 | | // Ensure the last item in |ivecs| is nonempty. This is necessary for |
314 | | // detecting being at the end and calling |f_final| at the appropriate time. |
315 | 5.40k | Span<IVec> ivecs_trimmed = ivecs; |
316 | 5.40k | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { |
317 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); |
318 | 0 | } |
319 | 5.40k | if (ivecs_trimmed.empty()) { |
320 | 0 | return call_func(f_final, IVec{}); |
321 | 0 | } |
322 | | |
323 | | // Now there are at least two non-empty |ivecs|, and neither the first nor the |
324 | | // last can be empty. |
325 | | |
326 | 5.40k | MutableIVec current_range_head = ivecs_trimmed.front(); |
327 | 5.40k | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); |
328 | 5.40k | while (!current_range_rest.empty()) { |
329 | | // Process as many whole blocks as possible. |
330 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; |
331 | 0 | if (whole_blocks_len != 0) { |
332 | 0 | MutableIVec whole_part = current_range_head; |
333 | 0 | whole_part.len = whole_blocks_len; |
334 | 0 | if (!call_func(f_whole, whole_part)) { |
335 | 0 | return false; |
336 | 0 | } |
337 | 0 | remove_prefix(current_range_head, whole_blocks_len); |
338 | 0 | } |
339 | | |
340 | 0 | if (current_range_head.len == 0) { |
341 | 0 | current_range_head = current_range_rest.front(); |
342 | 0 | current_range_rest = current_range_rest.subspan(1); |
343 | 0 | continue; |
344 | 0 | } |
345 | | |
346 | | // Collect a whole block. |
347 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; |
348 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; |
349 | 0 | MutableIVec collect_from_head = current_range_head; |
350 | 0 | Span<IVec> collect_from_rest = current_range_rest; |
351 | 0 | while (in.size() <= BlockSize) { |
352 | 0 | size_t remaining = BlockSize - in.size(); |
353 | 0 | if (remaining < collect_from_head.len) { |
354 | | // Got enough to complete the block _and more_. |
355 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); |
356 | 0 | remove_prefix(collect_from_head, remaining); |
357 | 0 | break; |
358 | 0 | } |
359 | | // Consume all of |ivec| and advance. |
360 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); |
361 | 0 | if (collect_from_rest.empty()) { |
362 | | // Nothing left - so this is the final block. |
363 | 0 | auto finalout = Span(out).first(in.size()); |
364 | 0 | MutableIVec finalvec = {}; |
365 | 0 | finalvec.len = in.size(); |
366 | 0 | finalvec.*ReadFrom = in.data(); |
367 | 0 | if constexpr (WriteOut) { |
368 | 0 | finalvec.out = finalout.data(); |
369 | 0 | } |
370 | 0 | if (!call_func(f_final, finalvec)) { |
371 | 0 | return false; |
372 | 0 | } |
373 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); |
374 | 0 | return true; |
375 | 0 | } |
376 | 0 | collect_from_head = collect_from_rest.front(); |
377 | 0 | collect_from_rest = collect_from_rest.subspan(1); |
378 | 0 | } |
379 | 0 | assert(in.size() == BlockSize); |
380 | | |
381 | | // The above loop ensures this condition by the |break| only happening if |
382 | | // |collect_from_head| has at least one byte remaining, and the loop |
383 | | // otherwise ensuring as an invariant that the final chunk - which is |
384 | | // nonempty - is among |collect_from_head| and |collect_from_rest|. |
385 | | // |
386 | | // As such, at least one byte is remaining, and thus calling |f_whole| is |
387 | | // appropriate. |
388 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); |
389 | | |
390 | | // Process the block. |
391 | 0 | MutableIVec wholevec = {}; |
392 | 0 | wholevec.len = in.size(); |
393 | 0 | wholevec.*ReadFrom = in.data(); |
394 | 0 | if constexpr (WriteOut) { |
395 | 0 | wholevec.out = out; |
396 | 0 | } |
397 | 0 | if (!call_func(f_whole, wholevec)) { |
398 | 0 | return false; |
399 | 0 | } |
400 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, |
401 | 0 | current_range_rest); |
402 | | |
403 | | // Set the new position. |
404 | 0 | current_range_head = collect_from_head; |
405 | 0 | current_range_rest = collect_from_rest; |
406 | 0 | } |
407 | | |
408 | | // If current_range_head.len is zero, then the last item of ivecs is empty. |
409 | | // That however was excluded at the start of the function to ensure |f_final| |
410 | | // is always used for the last call. |
411 | 5.40k | assert(current_range_head.len != 0); |
412 | | |
413 | 5.40k | return call_func(f_final, current_range_head); |
414 | 5.40k | } 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 | 287 | 137 | const FFinal &f_final) { | 288 | 137 | using MutableIVec = std::remove_const_t<IVec>; | 289 | | // Helper to make the function calls simpler. | 290 | 137 | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 137 | if constexpr (WriteOut) { | 292 | 137 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | 137 | } else { | 294 | 137 | return f(ivec.*ReadFrom, ivec.len); | 295 | 137 | } | 296 | 137 | }; | 297 | | // Helper to cut from the start of an IVec. | 298 | 137 | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 299 | 137 | ivec.*ReadFrom += by; | 300 | 137 | if constexpr (WriteOut) { | 301 | 137 | ivec.out += by; | 302 | 137 | } | 303 | 137 | ivec.len -= by; | 304 | 137 | }; | 305 | | // Helper to copy a range to an iovec list. | 306 | 137 | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 307 | 137 | Span<IVec> rest) { | 308 | 137 | if constexpr (WriteOut) { | 309 | 137 | internal::CopySpanToIOVec(out, head, rest); | 310 | 137 | } | 311 | 137 | }; | 312 | | | 313 | | // Ensure the last item in |ivecs| is nonempty. This is necessary for | 314 | | // detecting being at the end and calling |f_final| at the appropriate time. | 315 | 137 | Span<IVec> ivecs_trimmed = ivecs; | 316 | 137 | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 317 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 318 | 0 | } | 319 | 137 | if (ivecs_trimmed.empty()) { | 320 | 0 | return call_func(f_final, IVec{}); | 321 | 0 | } | 322 | | | 323 | | // Now there are at least two non-empty |ivecs|, and neither the first nor the | 324 | | // last can be empty. | 325 | | | 326 | 137 | MutableIVec current_range_head = ivecs_trimmed.front(); | 327 | 137 | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 328 | 137 | while (!current_range_rest.empty()) { | 329 | | // Process as many whole blocks as possible. | 330 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 331 | 0 | if (whole_blocks_len != 0) { | 332 | 0 | MutableIVec whole_part = current_range_head; | 333 | 0 | whole_part.len = whole_blocks_len; | 334 | 0 | if (!call_func(f_whole, whole_part)) { | 335 | 0 | return false; | 336 | 0 | } | 337 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 338 | 0 | } | 339 | | | 340 | 0 | if (current_range_head.len == 0) { | 341 | 0 | current_range_head = current_range_rest.front(); | 342 | 0 | current_range_rest = current_range_rest.subspan(1); | 343 | 0 | continue; | 344 | 0 | } | 345 | | | 346 | | // Collect a whole block. | 347 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 348 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 349 | 0 | MutableIVec collect_from_head = current_range_head; | 350 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 351 | 0 | while (in.size() <= BlockSize) { | 352 | 0 | size_t remaining = BlockSize - in.size(); | 353 | 0 | if (remaining < collect_from_head.len) { | 354 | | // Got enough to complete the block _and more_. | 355 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 356 | 0 | remove_prefix(collect_from_head, remaining); | 357 | 0 | break; | 358 | 0 | } | 359 | | // Consume all of |ivec| and advance. | 360 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 361 | 0 | if (collect_from_rest.empty()) { | 362 | | // Nothing left - so this is the final block. | 363 | 0 | auto finalout = Span(out).first(in.size()); | 364 | 0 | MutableIVec finalvec = {}; | 365 | 0 | finalvec.len = in.size(); | 366 | 0 | finalvec.*ReadFrom = in.data(); | 367 | 0 | if constexpr (WriteOut) { | 368 | 0 | finalvec.out = finalout.data(); | 369 | 0 | } | 370 | 0 | if (!call_func(f_final, finalvec)) { | 371 | 0 | return false; | 372 | 0 | } | 373 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 374 | 0 | return true; | 375 | 0 | } | 376 | 0 | collect_from_head = collect_from_rest.front(); | 377 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 378 | 0 | } | 379 | 0 | assert(in.size() == BlockSize); | 380 | | | 381 | | // The above loop ensures this condition by the |break| only happening if | 382 | | // |collect_from_head| has at least one byte remaining, and the loop | 383 | | // otherwise ensuring as an invariant that the final chunk - which is | 384 | | // nonempty - is among |collect_from_head| and |collect_from_rest|. | 385 | | // | 386 | | // As such, at least one byte is remaining, and thus calling |f_whole| is | 387 | | // appropriate. | 388 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 389 | | | 390 | | // Process the block. | 391 | 0 | MutableIVec wholevec = {}; | 392 | 0 | wholevec.len = in.size(); | 393 | 0 | wholevec.*ReadFrom = in.data(); | 394 | 0 | if constexpr (WriteOut) { | 395 | 0 | wholevec.out = out; | 396 | 0 | } | 397 | 0 | if (!call_func(f_whole, wholevec)) { | 398 | 0 | return false; | 399 | 0 | } | 400 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 401 | 0 | current_range_rest); | 402 | | | 403 | | // Set the new position. | 404 | 0 | current_range_head = collect_from_head; | 405 | 0 | current_range_rest = collect_from_rest; | 406 | 0 | } | 407 | | | 408 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 409 | | // That however was excluded at the start of the function to ensure |f_final| | 410 | | // is always used for the last call. | 411 | 137 | assert(current_range_head.len != 0); | 412 | | | 413 | 137 | return call_func(f_final, current_range_head); | 414 | 137 | } |
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 | 287 | 3.93k | const FFinal &f_final) { | 288 | 3.93k | using MutableIVec = std::remove_const_t<IVec>; | 289 | | // Helper to make the function calls simpler. | 290 | 3.93k | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 3.93k | if constexpr (WriteOut) { | 292 | 3.93k | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | 3.93k | } else { | 294 | 3.93k | return f(ivec.*ReadFrom, ivec.len); | 295 | 3.93k | } | 296 | 3.93k | }; | 297 | | // Helper to cut from the start of an IVec. | 298 | 3.93k | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 299 | 3.93k | ivec.*ReadFrom += by; | 300 | 3.93k | if constexpr (WriteOut) { | 301 | 3.93k | ivec.out += by; | 302 | 3.93k | } | 303 | 3.93k | ivec.len -= by; | 304 | 3.93k | }; | 305 | | // Helper to copy a range to an iovec list. | 306 | 3.93k | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 307 | 3.93k | Span<IVec> rest) { | 308 | 3.93k | if constexpr (WriteOut) { | 309 | 3.93k | internal::CopySpanToIOVec(out, head, rest); | 310 | 3.93k | } | 311 | 3.93k | }; | 312 | | | 313 | | // Ensure the last item in |ivecs| is nonempty. This is necessary for | 314 | | // detecting being at the end and calling |f_final| at the appropriate time. | 315 | 3.93k | Span<IVec> ivecs_trimmed = ivecs; | 316 | 3.93k | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 317 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 318 | 0 | } | 319 | 3.93k | if (ivecs_trimmed.empty()) { | 320 | 0 | return call_func(f_final, IVec{}); | 321 | 0 | } | 322 | | | 323 | | // Now there are at least two non-empty |ivecs|, and neither the first nor the | 324 | | // last can be empty. | 325 | | | 326 | 3.93k | MutableIVec current_range_head = ivecs_trimmed.front(); | 327 | 3.93k | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 328 | 3.93k | while (!current_range_rest.empty()) { | 329 | | // Process as many whole blocks as possible. | 330 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 331 | 0 | if (whole_blocks_len != 0) { | 332 | 0 | MutableIVec whole_part = current_range_head; | 333 | 0 | whole_part.len = whole_blocks_len; | 334 | 0 | if (!call_func(f_whole, whole_part)) { | 335 | 0 | return false; | 336 | 0 | } | 337 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 338 | 0 | } | 339 | | | 340 | 0 | if (current_range_head.len == 0) { | 341 | 0 | current_range_head = current_range_rest.front(); | 342 | 0 | current_range_rest = current_range_rest.subspan(1); | 343 | 0 | continue; | 344 | 0 | } | 345 | | | 346 | | // Collect a whole block. | 347 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 348 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 349 | 0 | MutableIVec collect_from_head = current_range_head; | 350 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 351 | 0 | while (in.size() <= BlockSize) { | 352 | 0 | size_t remaining = BlockSize - in.size(); | 353 | 0 | if (remaining < collect_from_head.len) { | 354 | | // Got enough to complete the block _and more_. | 355 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 356 | 0 | remove_prefix(collect_from_head, remaining); | 357 | 0 | break; | 358 | 0 | } | 359 | | // Consume all of |ivec| and advance. | 360 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 361 | 0 | if (collect_from_rest.empty()) { | 362 | | // Nothing left - so this is the final block. | 363 | 0 | auto finalout = Span(out).first(in.size()); | 364 | 0 | MutableIVec finalvec = {}; | 365 | 0 | finalvec.len = in.size(); | 366 | 0 | finalvec.*ReadFrom = in.data(); | 367 | 0 | if constexpr (WriteOut) { | 368 | 0 | finalvec.out = finalout.data(); | 369 | 0 | } | 370 | 0 | if (!call_func(f_final, finalvec)) { | 371 | 0 | return false; | 372 | 0 | } | 373 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 374 | 0 | return true; | 375 | 0 | } | 376 | 0 | collect_from_head = collect_from_rest.front(); | 377 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 378 | 0 | } | 379 | 0 | assert(in.size() == BlockSize); | 380 | | | 381 | | // The above loop ensures this condition by the |break| only happening if | 382 | | // |collect_from_head| has at least one byte remaining, and the loop | 383 | | // otherwise ensuring as an invariant that the final chunk - which is | 384 | | // nonempty - is among |collect_from_head| and |collect_from_rest|. | 385 | | // | 386 | | // As such, at least one byte is remaining, and thus calling |f_whole| is | 387 | | // appropriate. | 388 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 389 | | | 390 | | // Process the block. | 391 | 0 | MutableIVec wholevec = {}; | 392 | 0 | wholevec.len = in.size(); | 393 | 0 | wholevec.*ReadFrom = in.data(); | 394 | 0 | if constexpr (WriteOut) { | 395 | 0 | wholevec.out = out; | 396 | 0 | } | 397 | 0 | if (!call_func(f_whole, wholevec)) { | 398 | 0 | return false; | 399 | 0 | } | 400 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 401 | 0 | current_range_rest); | 402 | | | 403 | | // Set the new position. | 404 | 0 | current_range_head = collect_from_head; | 405 | 0 | current_range_rest = collect_from_rest; | 406 | 0 | } | 407 | | | 408 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 409 | | // That however was excluded at the start of the function to ensure |f_final| | 410 | | // is always used for the last call. | 411 | 3.93k | assert(current_range_head.len != 0); | 412 | | | 413 | 3.93k | return call_func(f_final, current_range_head); | 414 | 3.93k | } |
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 | 287 | 626 | const FFinal &f_final) { | 288 | 626 | using MutableIVec = std::remove_const_t<IVec>; | 289 | | // Helper to make the function calls simpler. | 290 | 626 | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 626 | if constexpr (WriteOut) { | 292 | 626 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | 626 | } else { | 294 | 626 | return f(ivec.*ReadFrom, ivec.len); | 295 | 626 | } | 296 | 626 | }; | 297 | | // Helper to cut from the start of an IVec. | 298 | 626 | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 299 | 626 | ivec.*ReadFrom += by; | 300 | 626 | if constexpr (WriteOut) { | 301 | 626 | ivec.out += by; | 302 | 626 | } | 303 | 626 | ivec.len -= by; | 304 | 626 | }; | 305 | | // Helper to copy a range to an iovec list. | 306 | 626 | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 307 | 626 | Span<IVec> rest) { | 308 | 626 | if constexpr (WriteOut) { | 309 | 626 | internal::CopySpanToIOVec(out, head, rest); | 310 | 626 | } | 311 | 626 | }; | 312 | | | 313 | | // Ensure the last item in |ivecs| is nonempty. This is necessary for | 314 | | // detecting being at the end and calling |f_final| at the appropriate time. | 315 | 626 | Span<IVec> ivecs_trimmed = ivecs; | 316 | 626 | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 317 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 318 | 0 | } | 319 | 626 | if (ivecs_trimmed.empty()) { | 320 | 0 | return call_func(f_final, IVec{}); | 321 | 0 | } | 322 | | | 323 | | // Now there are at least two non-empty |ivecs|, and neither the first nor the | 324 | | // last can be empty. | 325 | | | 326 | 626 | MutableIVec current_range_head = ivecs_trimmed.front(); | 327 | 626 | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 328 | 626 | while (!current_range_rest.empty()) { | 329 | | // Process as many whole blocks as possible. | 330 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 331 | 0 | if (whole_blocks_len != 0) { | 332 | 0 | MutableIVec whole_part = current_range_head; | 333 | 0 | whole_part.len = whole_blocks_len; | 334 | 0 | if (!call_func(f_whole, whole_part)) { | 335 | 0 | return false; | 336 | 0 | } | 337 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 338 | 0 | } | 339 | | | 340 | 0 | if (current_range_head.len == 0) { | 341 | 0 | current_range_head = current_range_rest.front(); | 342 | 0 | current_range_rest = current_range_rest.subspan(1); | 343 | 0 | continue; | 344 | 0 | } | 345 | | | 346 | | // Collect a whole block. | 347 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 348 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 349 | 0 | MutableIVec collect_from_head = current_range_head; | 350 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 351 | 0 | while (in.size() <= BlockSize) { | 352 | 0 | size_t remaining = BlockSize - in.size(); | 353 | 0 | if (remaining < collect_from_head.len) { | 354 | | // Got enough to complete the block _and more_. | 355 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 356 | 0 | remove_prefix(collect_from_head, remaining); | 357 | 0 | break; | 358 | 0 | } | 359 | | // Consume all of |ivec| and advance. | 360 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 361 | 0 | if (collect_from_rest.empty()) { | 362 | | // Nothing left - so this is the final block. | 363 | 0 | auto finalout = Span(out).first(in.size()); | 364 | 0 | MutableIVec finalvec = {}; | 365 | 0 | finalvec.len = in.size(); | 366 | 0 | finalvec.*ReadFrom = in.data(); | 367 | 0 | if constexpr (WriteOut) { | 368 | 0 | finalvec.out = finalout.data(); | 369 | 0 | } | 370 | 0 | if (!call_func(f_final, finalvec)) { | 371 | 0 | return false; | 372 | 0 | } | 373 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 374 | 0 | return true; | 375 | 0 | } | 376 | 0 | collect_from_head = collect_from_rest.front(); | 377 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 378 | 0 | } | 379 | 0 | assert(in.size() == BlockSize); | 380 | | | 381 | | // The above loop ensures this condition by the |break| only happening if | 382 | | // |collect_from_head| has at least one byte remaining, and the loop | 383 | | // otherwise ensuring as an invariant that the final chunk - which is | 384 | | // nonempty - is among |collect_from_head| and |collect_from_rest|. | 385 | | // | 386 | | // As such, at least one byte is remaining, and thus calling |f_whole| is | 387 | | // appropriate. | 388 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 389 | | | 390 | | // Process the block. | 391 | 0 | MutableIVec wholevec = {}; | 392 | 0 | wholevec.len = in.size(); | 393 | 0 | wholevec.*ReadFrom = in.data(); | 394 | 0 | if constexpr (WriteOut) { | 395 | 0 | wholevec.out = out; | 396 | 0 | } | 397 | 0 | if (!call_func(f_whole, wholevec)) { | 398 | 0 | return false; | 399 | 0 | } | 400 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 401 | 0 | current_range_rest); | 402 | | | 403 | | // Set the new position. | 404 | 0 | current_range_head = collect_from_head; | 405 | 0 | current_range_rest = collect_from_rest; | 406 | 0 | } | 407 | | | 408 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 409 | | // That however was excluded at the start of the function to ensure |f_final| | 410 | | // is always used for the last call. | 411 | 626 | assert(current_range_head.len != 0); | 412 | | | 413 | 626 | return call_func(f_final, current_range_head); | 414 | 626 | } |
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 | 287 | 714 | const FFinal &f_final) { | 288 | 714 | using MutableIVec = std::remove_const_t<IVec>; | 289 | | // Helper to make the function calls simpler. | 290 | 714 | auto call_func = [&](const auto &f, const IVec &ivec) { | 291 | 714 | if constexpr (WriteOut) { | 292 | 714 | return f(ivec.*ReadFrom, ivec.out, ivec.len); | 293 | 714 | } else { | 294 | 714 | return f(ivec.*ReadFrom, ivec.len); | 295 | 714 | } | 296 | 714 | }; | 297 | | // Helper to cut from the start of an IVec. | 298 | 714 | auto remove_prefix = [&](MutableIVec &ivec, size_t by) { | 299 | 714 | ivec.*ReadFrom += by; | 300 | 714 | if constexpr (WriteOut) { | 301 | 714 | ivec.out += by; | 302 | 714 | } | 303 | 714 | ivec.len -= by; | 304 | 714 | }; | 305 | | // Helper to copy a range to an iovec list. | 306 | 714 | auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head, | 307 | 714 | Span<IVec> rest) { | 308 | 714 | if constexpr (WriteOut) { | 309 | 714 | internal::CopySpanToIOVec(out, head, rest); | 310 | 714 | } | 311 | 714 | }; | 312 | | | 313 | | // Ensure the last item in |ivecs| is nonempty. This is necessary for | 314 | | // detecting being at the end and calling |f_final| at the appropriate time. | 315 | 714 | Span<IVec> ivecs_trimmed = ivecs; | 316 | 714 | while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) { | 317 | 0 | ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1); | 318 | 0 | } | 319 | 714 | if (ivecs_trimmed.empty()) { | 320 | 0 | return call_func(f_final, IVec{}); | 321 | 0 | } | 322 | | | 323 | | // Now there are at least two non-empty |ivecs|, and neither the first nor the | 324 | | // last can be empty. | 325 | | | 326 | 714 | MutableIVec current_range_head = ivecs_trimmed.front(); | 327 | 714 | Span<IVec> current_range_rest = ivecs_trimmed.subspan(1); | 328 | 714 | while (!current_range_rest.empty()) { | 329 | | // Process as many whole blocks as possible. | 330 | 0 | size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize; | 331 | 0 | if (whole_blocks_len != 0) { | 332 | 0 | MutableIVec whole_part = current_range_head; | 333 | 0 | whole_part.len = whole_blocks_len; | 334 | 0 | if (!call_func(f_whole, whole_part)) { | 335 | 0 | return false; | 336 | 0 | } | 337 | 0 | remove_prefix(current_range_head, whole_blocks_len); | 338 | 0 | } | 339 | | | 340 | 0 | if (current_range_head.len == 0) { | 341 | 0 | current_range_head = current_range_rest.front(); | 342 | 0 | current_range_rest = current_range_rest.subspan(1); | 343 | 0 | continue; | 344 | 0 | } | 345 | | | 346 | | // Collect a whole block. | 347 | 0 | alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in; | 348 | 0 | alignas(BlockSize) uint8_t out[BlockSize]; | 349 | 0 | MutableIVec collect_from_head = current_range_head; | 350 | 0 | Span<IVec> collect_from_rest = current_range_rest; | 351 | 0 | while (in.size() <= BlockSize) { | 352 | 0 | size_t remaining = BlockSize - in.size(); | 353 | 0 | if (remaining < collect_from_head.len) { | 354 | | // Got enough to complete the block _and more_. | 355 | 0 | in.Append(Span(collect_from_head.*ReadFrom, remaining)); | 356 | 0 | remove_prefix(collect_from_head, remaining); | 357 | 0 | break; | 358 | 0 | } | 359 | | // Consume all of |ivec| and advance. | 360 | 0 | in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len)); | 361 | 0 | if (collect_from_rest.empty()) { | 362 | | // Nothing left - so this is the final block. | 363 | 0 | auto finalout = Span(out).first(in.size()); | 364 | 0 | MutableIVec finalvec = {}; | 365 | 0 | finalvec.len = in.size(); | 366 | 0 | finalvec.*ReadFrom = in.data(); | 367 | 0 | if constexpr (WriteOut) { | 368 | 0 | finalvec.out = finalout.data(); | 369 | 0 | } | 370 | 0 | if (!call_func(f_final, finalvec)) { | 371 | 0 | return false; | 372 | 0 | } | 373 | 0 | maybe_copy_to_iovec(finalout, current_range_head, current_range_rest); | 374 | 0 | return true; | 375 | 0 | } | 376 | 0 | collect_from_head = collect_from_rest.front(); | 377 | 0 | collect_from_rest = collect_from_rest.subspan(1); | 378 | 0 | } | 379 | 0 | assert(in.size() == BlockSize); | 380 | | | 381 | | // The above loop ensures this condition by the |break| only happening if | 382 | | // |collect_from_head| has at least one byte remaining, and the loop | 383 | | // otherwise ensuring as an invariant that the final chunk - which is | 384 | | // nonempty - is among |collect_from_head| and |collect_from_rest|. | 385 | | // | 386 | | // As such, at least one byte is remaining, and thus calling |f_whole| is | 387 | | // appropriate. | 388 | 0 | assert(collect_from_head.len != 0 || !collect_from_rest.empty()); | 389 | | | 390 | | // Process the block. | 391 | 0 | MutableIVec wholevec = {}; | 392 | 0 | wholevec.len = in.size(); | 393 | 0 | wholevec.*ReadFrom = in.data(); | 394 | 0 | if constexpr (WriteOut) { | 395 | 0 | wholevec.out = out; | 396 | 0 | } | 397 | 0 | if (!call_func(f_whole, wholevec)) { | 398 | 0 | return false; | 399 | 0 | } | 400 | 0 | maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head, | 401 | 0 | current_range_rest); | 402 | | | 403 | | // Set the new position. | 404 | 0 | current_range_head = collect_from_head; | 405 | 0 | current_range_rest = collect_from_rest; | 406 | 0 | } | 407 | | | 408 | | // If current_range_head.len is zero, then the last item of ivecs is empty. | 409 | | // That however was excluded at the start of the function to ensure |f_final| | 410 | | // is always used for the last call. | 411 | 714 | assert(current_range_head.len != 0); | 412 | | | 413 | 714 | return call_func(f_final, current_range_head); | 414 | 714 | } |
|
415 | | |
416 | | // ForEachOutBlockRange is like |ForEachBlockRange| but reads from a |
417 | | // |CRYPTO_IOVEC|'s |out| member instead. |
418 | | template < |
419 | | size_t BlockSize, |
420 | | typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole, |
421 | | typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */ |
422 | | FFinal> |
423 | | inline int ForEachOutBlockRange(Span<const CRYPTO_IOVEC> iovecs, |
424 | 0 | const FWhole &f_whole, const FFinal &f_final) { |
425 | 0 | return ForEachBlockRange<BlockSize, /*WriteOut=*/false, const CRYPTO_IOVEC, |
426 | 0 | /*ReadFromT=*/uint8_t *, |
427 | 0 | /*ReadFrom=*/&CRYPTO_IOVEC::out>(iovecs, f_whole, |
428 | 0 | f_final); |
429 | 0 | } |
430 | | |
431 | | // ForEachBlockRange_Dynamic is simply |ForEachBlockRange| with a |
432 | | // runtime dispatch on the block size. |
433 | | template < |
434 | | bool WriteOut = false, typename IVec, typename ReadFromT = const uint8_t *, |
435 | | ReadFromT IVec::*ReadFrom = &IVec::in, |
436 | | typename /* int(const uint8_t *in, uint8_t *out, size_t len) */ FWhole, |
437 | | typename /* int(const uint8_t *in, uint8_t *out, size_t len) */ |
438 | | FFinal> |
439 | | inline int ForEachBlockRange_Dynamic(size_t block_size, Span<IVec> ivecs, |
440 | | const FWhole &f_whole, |
441 | 5.40k | const FFinal &f_final) { |
442 | 5.40k | switch (block_size) { |
443 | 763 | case 8: |
444 | 763 | return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>( |
445 | 763 | ivecs, f_whole, f_final); |
446 | 0 | break; |
447 | 4.64k | case 16: |
448 | 4.64k | return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>( |
449 | 4.64k | ivecs, f_whole, f_final); |
450 | 0 | break; |
451 | 0 | default: |
452 | 0 | return 0; |
453 | 5.40k | } |
454 | 5.40k | } 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 | 441 | 4.06k | const FFinal &f_final) { | 442 | 4.06k | switch (block_size) { | 443 | 137 | case 8: | 444 | 137 | return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>( | 445 | 137 | ivecs, f_whole, f_final); | 446 | 0 | break; | 447 | 3.93k | case 16: | 448 | 3.93k | return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>( | 449 | 3.93k | ivecs, f_whole, f_final); | 450 | 0 | break; | 451 | 0 | default: | 452 | 0 | return 0; | 453 | 4.06k | } | 454 | 4.06k | } |
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 | 441 | 1.34k | const FFinal &f_final) { | 442 | 1.34k | switch (block_size) { | 443 | 626 | case 8: | 444 | 626 | return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>( | 445 | 626 | ivecs, f_whole, f_final); | 446 | 0 | break; | 447 | 714 | case 16: | 448 | 714 | return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>( | 449 | 714 | ivecs, f_whole, f_final); | 450 | 0 | break; | 451 | 0 | default: | 452 | 0 | return 0; | 453 | 1.34k | } | 454 | 1.34k | } |
|
455 | | |
456 | | } // namespace iovec |
457 | | |
458 | | BSSL_NAMESPACE_END |
459 | | |
460 | | #endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H |