veilid_core/crypto/guard.rs
1use core::marker::PhantomData;
2use std::ops::Range;
3
4use super::*;
5
6/// Guard to access a particular cryptosystem
7///
8/// Holds an `Arc` to the cryptosystem for its whole lifetime; the cryptosystem stays reachable as
9/// long as the guard (or its derived [`AsyncCryptoSystemGuard`]) is alive.
10#[must_use]
11pub struct CryptoSystemGuard<'a> {
12 crypto_system: Arc<dyn CryptoSystem + Send + Sync>,
13 _phantom: core::marker::PhantomData<&'a (dyn CryptoSystem + Send + Sync)>,
14}
15
16impl<'a> CryptoSystemGuard<'a> {
17 pub(super) fn new(crypto_system: Arc<dyn CryptoSystem + Send + Sync>) -> Self {
18 Self {
19 crypto_system,
20 _phantom: PhantomData,
21 }
22 }
23 /// Convert into an async guard whose operations yield to the executor between work units.
24 ///
25 /// Consumes this guard, moving its held cryptosystem `Arc` into the returned async guard.
26 pub fn as_async(self) -> AsyncCryptoSystemGuard<'a> {
27 AsyncCryptoSystemGuard { guard: self }
28 }
29 /// Get a clone of the inner Arc for use in blocking tasks
30 pub(super) fn clone_arc(&self) -> Arc<dyn CryptoSystem + Send + Sync> {
31 self.crypto_system.clone()
32 }
33}
34
35impl core::ops::Deref for CryptoSystemGuard<'_> {
36 type Target = dyn CryptoSystem + Send + Sync;
37
38 fn deref(&self) -> &Self::Target {
39 self.crypto_system.as_ref()
40 }
41}
42
43/// Async cryptosystem guard to help break up heavy blocking operations
44#[must_use]
45pub struct AsyncCryptoSystemGuard<'a> {
46 guard: CryptoSystemGuard<'a>,
47}
48
49impl AsyncCryptoSystemGuard<'_> {
50 // Accessors
51
52 /// The `CryptoKind` of the guarded cryptosystem.
53 pub fn kind(&self) -> CryptoKind {
54 self.guard.kind()
55 }
56 /// Get a guard on the `Crypto` component that owns this cryptosystem.
57 #[must_use]
58 pub fn crypto(&self) -> VeilidComponentGuard<'_, Crypto> {
59 self.guard.crypto()
60 }
61
62 // Cached Operations
63
64 /// Diffie-Hellman shared secret, served from the `Crypto` DH cache when present.
65 ///
66 /// Local CPU only; awaits a single runtime yield. On a cache miss runs the DH inline (does not
67 /// offload to the rayon pool, unlike [`compute_dh`](Self::compute_dh)).
68 ///
69 /// Errors `VeilidAPIError::Generic` if `key` or `secret` carries the wrong kind or length, or
70 /// (on a cache miss) `VeilidAPIError::Internal` if `key` is not a valid curve point and
71 /// `VeilidAPIError::Generic` if the exchange is non-contributory.
72 pub async fn cached_dh(
73 &self,
74 key: &PublicKey,
75 secret: &SecretKey,
76 ) -> VeilidAPIResult<SharedSecret> {
77 yielding(|| self.guard.cached_dh(key, secret)).await
78 }
79
80 // Generation
81
82 /// Generate `len` cryptographically random bytes.
83 pub async fn random_bytes(&self, len: usize) -> Bytes {
84 yielding(|| self.guard.random_bytes(len).into()).await
85 }
86
87 /// Hash a password with the given salt, producing a verifier string.
88 ///
89 /// CPU-heavy (Argon2); offloaded to the rayon thread pool off-WASM. No network or disk.
90 ///
91 /// Errors `VeilidAPIError::Generic` if `salt` length is outside the Argon2 bounds or the KDF
92 /// fails, `VeilidAPIError::ParseError` if the salt fails base64 encoding.
93 pub async fn hash_password(&self, password: Bytes, salt: Bytes) -> VeilidAPIResult<String> {
94 let cs = self.guard.clone_arc();
95 let salt = salt.to_vec();
96 cpu_yielding(move || cs.hash_password(&password, &salt)).await
97 }
98 /// Verify a password against a hash produced by `hash_password`.
99 ///
100 /// CPU-heavy (Argon2); offloaded to the rayon thread pool off-WASM. No network or disk.
101 ///
102 /// Returns `Ok(false)` on mismatch. Errors `VeilidAPIError::ParseError` if `password_hash` is
103 /// not a valid PHC string.
104 pub async fn verify_password(
105 &self,
106 password: Bytes,
107 password_hash: &str,
108 ) -> VeilidAPIResult<bool> {
109 let cs = self.guard.clone_arc();
110 let password_hash = password_hash.to_string();
111 cpu_yielding(move || cs.verify_password(&password, &password_hash)).await
112 }
113 /// Derive a shared secret deterministically from a password and salt.
114 ///
115 /// CPU-heavy (Argon2) but run inline before a single yield (not offloaded), so it holds the
116 /// thread for the full KDF. No network or disk.
117 ///
118 /// Errors `VeilidAPIError::Generic` if `salt` length is outside the Argon2 bounds or the KDF fails.
119 pub async fn derive_shared_secret(
120 &self,
121 password: Bytes,
122 salt: Bytes,
123 ) -> VeilidAPIResult<SharedSecret> {
124 yielding(|| self.guard.derive_shared_secret(&password, &salt)).await
125 }
126 /// Generate a random nonce.
127 pub async fn random_nonce(&self) -> Nonce {
128 yielding(|| self.guard.random_nonce()).await
129 }
130 /// Generate a random shared secret.
131 pub async fn random_shared_secret(&self) -> SharedSecret {
132 yielding(|| self.guard.random_shared_secret()).await
133 }
134 /// Compute the Diffie-Hellman shared secret for a public key and secret key.
135 ///
136 /// Local CPU only, offloaded to the rayon thread pool off-WASM; uncached, recomputes every call.
137 /// Use [`cached_dh`](Self::cached_dh) to memoize.
138 ///
139 /// Errors `VeilidAPIError::Internal` if `key` is not a valid curve point, `VeilidAPIError::Generic`
140 /// if the exchange is non-contributory (low-order public key).
141 pub async fn compute_dh(
142 &self,
143 key: &PublicKey,
144 secret: &SecretKey,
145 ) -> VeilidAPIResult<SharedSecret> {
146 let cs = self.guard.clone_arc();
147 let key = key.clone();
148 let secret = secret.clone();
149 cpu_yielding(move || cs.compute_dh(&key, &secret)).await
150 }
151 /// Derive a domain-separated shared secret by hashing the DH result together with `domain` and the Veilid API domain.
152 ///
153 /// Local CPU only; the DH step is offloaded to the rayon thread pool off-WASM (see
154 /// [`compute_dh`](Self::compute_dh)).
155 ///
156 /// Errors with the [`compute_dh`](Self::compute_dh) errors if the key exchange fails.
157 pub async fn generate_shared_secret(
158 &self,
159 key: &PublicKey,
160 secret: &SecretKey,
161 domain: Bytes,
162 ) -> VeilidAPIResult<SharedSecret> {
163 let dh = self.compute_dh(key, secret).await?;
164 let data = [
165 dh.ref_value().bytes().as_ref(),
166 domain.as_ref(),
167 VEILID_DOMAIN_API,
168 ]
169 .concat()
170 .into();
171 let hash = self.generate_hash(data).await;
172 Ok(SharedSecret::new(
173 hash.kind(),
174 BareSharedSecret::new(&hash.into_value()),
175 ))
176 }
177
178 /// Seal a plaintext to a recipient KEM encapsulation key with HPKE base mode (RFC 9180),
179 /// single-shot. `aad` is authenticated but not encrypted. Returns a self-describing sealed blob.
180 ///
181 /// Sealing is one-way: only the recipient can open the blob, and the sealer cannot decrypt
182 /// what it just sealed, unlike the DH shared-secret pattern. Callers who already share a
183 /// symmetric key want [`encrypt_aead`](Self::encrypt_aead) instead.
184 ///
185 /// Local CPU only, offloaded to the rayon thread pool off-WASM (a KEM encapsulation always runs).
186 ///
187 /// Errors `VeilidAPIError::InvalidArgument` if `recipient` is not a valid key,
188 /// `VeilidAPIError::Generic` if encapsulation fails (including a low-order key).
189 pub async fn hpke_seal(
190 &self,
191 recipient: &EncapsulationKey,
192 aad: Bytes,
193 plaintext: Bytes,
194 ) -> VeilidAPIResult<Bytes> {
195 let cs = self.guard.clone_arc();
196 let recipient = recipient.clone();
197 cpu_yielding(move || Ok(cs.hpke_seal(&recipient, &aad, &plaintext)?.into())).await
198 }
199
200 /// Open a sealed blob produced by [`hpke_seal`](Self::hpke_seal) with the recipient KEM
201 /// decapsulation key. `aad` must match what was supplied at seal. Only the recipient can
202 /// open a sealed blob; the sealer cannot.
203 ///
204 /// Local CPU only, offloaded to the rayon thread pool off-WASM (a KEM decapsulation always runs).
205 ///
206 /// Errors `VeilidAPIError::ParseError` if the blob is truncated or its version is unknown,
207 /// `VeilidAPIError::InvalidArgument` if the blob's kind is not this cryptosystem's kind or
208 /// `secret` is not a valid key, `VeilidAPIError::Generic` if decryption fails (tampered blob,
209 /// wrong recipient, or mismatched `aad`).
210 pub async fn hpke_open(
211 &self,
212 secret: &DecapsulationKey,
213 aad: Bytes,
214 sealed: Bytes,
215 ) -> VeilidAPIResult<Bytes> {
216 let cs = self.guard.clone_arc();
217 let secret = secret.clone();
218 cpu_yielding(move || Ok(cs.hpke_open(&secret, &aad, &sealed)?.into())).await
219 }
220
221 /// Generate a new keypair.
222 pub async fn generate_keypair(&self) -> KeyPair {
223 yielding(|| self.guard.generate_keypair()).await
224 }
225
226 /// Generate a new KEM key pair.
227 pub async fn generate_kem_keypair(&self) -> KemKeyPair {
228 yielding(|| self.guard.generate_kem_keypair()).await
229 }
230
231 /// Derive the KEM encapsulation key corresponding to a signing public key.
232 ///
233 /// VLD0-only bridge (ed25519 to x25519); kinds whose signing and KEM keys are unrelated error
234 /// `VeilidAPIError::Unimplemented`.
235 ///
236 /// Errors `VeilidAPIError::InvalidArgument` if `key` is not a valid signing public key.
237 pub async fn encapsulation_key_from_signing_key(
238 &self,
239 key: &PublicKey,
240 ) -> VeilidAPIResult<EncapsulationKey> {
241 yielding(|| self.guard.encapsulation_key_from_signing_key(key)).await
242 }
243
244 /// Derive the KEM decapsulation key corresponding to a signing secret key.
245 ///
246 /// VLD0-only bridge (ed25519 to x25519); kinds whose signing and KEM keys are unrelated error
247 /// `VeilidAPIError::Unimplemented`.
248 ///
249 /// Errors `VeilidAPIError::InvalidArgument` if `secret` is not a valid signing secret key.
250 pub async fn decapsulation_key_from_signing_secret(
251 &self,
252 secret: &SecretKey,
253 ) -> VeilidAPIResult<DecapsulationKey> {
254 yielding(|| self.guard.decapsulation_key_from_signing_secret(secret)).await
255 }
256
257 /// Hash a byte buffer.
258 pub async fn generate_hash(&self, data: Bytes) -> HashDigest {
259 yielding(|| self.guard.generate_hash(&data)).await
260 }
261
262 /// Hash the entire contents of a reader.
263 ///
264 /// Errors `VeilidAPIError::Generic` if reading from `reader` fails.
265 pub async fn generate_hash_reader(
266 &self,
267 reader: &mut dyn std::io::Read,
268 ) -> VeilidAPIResult<PublicKey> {
269 yielding(|| self.guard.generate_hash_reader(reader)).await
270 }
271
272 // Validation
273
274 /// Length in bytes of a shared secret.
275 #[must_use]
276 pub fn shared_secret_length(&self) -> usize {
277 self.guard.shared_secret_length()
278 }
279 /// Length in bytes of a nonce.
280 #[must_use]
281 pub fn nonce_length(&self) -> usize {
282 self.guard.nonce_length()
283 }
284 /// Length in bytes of a hash digest.
285 #[must_use]
286 pub fn hash_digest_length(&self) -> usize {
287 self.guard.hash_digest_length()
288 }
289 /// Length in bytes of a public key.
290 #[must_use]
291 pub fn public_key_length(&self) -> usize {
292 self.guard.public_key_length()
293 }
294 /// Length in bytes of a secret key.
295 #[must_use]
296 pub fn secret_key_length(&self) -> usize {
297 self.guard.secret_key_length()
298 }
299 /// Length in bytes of a KEM encapsulation key.
300 #[must_use]
301 pub fn encapsulation_key_length(&self) -> usize {
302 self.guard.encapsulation_key_length()
303 }
304 /// Length in bytes of a KEM decapsulation key.
305 #[must_use]
306 pub fn decapsulation_key_length(&self) -> usize {
307 self.guard.decapsulation_key_length()
308 }
309 /// Length in bytes of a signature.
310 #[must_use]
311 pub fn signature_length(&self) -> usize {
312 self.guard.signature_length()
313 }
314 /// Number of extra bytes an AEAD operation adds to the ciphertext.
315 #[must_use]
316 pub fn aead_overhead(&self) -> usize {
317 self.guard.aead_overhead()
318 }
319 /// Default salt length in bytes for password hashing.
320 #[must_use]
321 pub fn default_salt_length(&self) -> usize {
322 self.guard.default_salt_length()
323 }
324 /// Validate that a shared secret is well-formed for this cryptosystem.
325 ///
326 /// Errors `VeilidAPIError::Generic` if `secret` has the wrong kind or length.
327 pub fn check_shared_secret(&self, secret: &SharedSecret) -> VeilidAPIResult<()> {
328 self.guard.check_shared_secret(secret)
329 }
330 /// Validate that a nonce is well-formed for this cryptosystem.
331 ///
332 /// Errors `VeilidAPIError::Generic` if `nonce` has the wrong length.
333 pub fn check_nonce(&self, nonce: &Nonce) -> VeilidAPIResult<()> {
334 self.guard.check_nonce(nonce)
335 }
336 /// Validate that a hash digest is well-formed for this cryptosystem.
337 ///
338 /// Errors `VeilidAPIError::Generic` if `hash` has the wrong kind or length.
339 pub fn check_hash_digest(&self, hash: &HashDigest) -> VeilidAPIResult<()> {
340 self.guard.check_hash_digest(hash)
341 }
342 /// Validate that a public key is well-formed for this cryptosystem.
343 ///
344 /// Errors `VeilidAPIError::Generic` if `key` has the wrong kind or length.
345 pub fn check_public_key(&self, key: &PublicKey) -> VeilidAPIResult<()> {
346 self.guard.check_public_key(key)
347 }
348 /// Validate that a secret key is well-formed for this cryptosystem.
349 ///
350 /// Errors `VeilidAPIError::Generic` if `key` has the wrong kind or length.
351 pub fn check_secret_key(&self, key: &SecretKey) -> VeilidAPIResult<()> {
352 self.guard.check_secret_key(key)
353 }
354 /// Validate that a signature is well-formed for this cryptosystem.
355 ///
356 /// Errors `VeilidAPIError::Generic` if `signature` has the wrong kind or length.
357 pub fn check_signature(&self, signature: &Signature) -> VeilidAPIResult<()> {
358 self.guard.check_signature(signature)
359 }
360 /// Validate that a keypair is well-formed for this cryptosystem. Structural check only; see
361 /// [`validate_keypair`](Self::validate_keypair).
362 ///
363 /// Errors `VeilidAPIError::Generic` if the pair or either key has the wrong kind or length.
364 pub fn check_keypair(&self, keypair: &KeyPair) -> VeilidAPIResult<()> {
365 self.guard.check_keypair(keypair)
366 }
367 /// Check that a public key and secret key form a valid keypair.
368 ///
369 /// Returns `Ok(false)` if they do not match. Errors `VeilidAPIError::Generic` if `key` or
370 /// `secret` has the wrong kind or length.
371 pub async fn validate_keypair(
372 &self,
373 key: &PublicKey,
374 secret: &SecretKey,
375 ) -> VeilidAPIResult<bool> {
376 yielding(|| self.guard.validate_keypair(key, secret)).await
377 }
378
379 /// Check that a buffer hashes to the given digest.
380 ///
381 /// Errors `VeilidAPIError::Generic` if `hash` has the wrong kind or length.
382 pub async fn validate_hash(&self, data: Bytes, hash: &HashDigest) -> VeilidAPIResult<bool> {
383 yielding(|| self.guard.validate_hash(&data, hash)).await
384 }
385
386 /// Check that a reader's contents hash to the given digest.
387 ///
388 /// Errors `VeilidAPIError::Generic` if `hash` has the wrong kind or length, or if reading from
389 /// `reader` fails.
390 pub async fn validate_hash_reader(
391 &self,
392 reader: &mut dyn std::io::Read,
393 hash: &HashDigest,
394 ) -> VeilidAPIResult<bool> {
395 yielding(|| self.guard.validate_hash_reader(reader, hash)).await
396 }
397
398 // Authentication
399
400 /// Sign a buffer with a keypair, returning a detached signature.
401 ///
402 /// Local CPU only, offloaded to the rayon thread pool off-WASM.
403 ///
404 /// Errors `VeilidAPIError::Generic` if `public_key` or `secret` has the wrong kind or length,
405 /// `VeilidAPIError::ParseError` if they do not form a valid ed25519 keypair,
406 /// `VeilidAPIError::Internal` if signing fails.
407 pub async fn sign(
408 &self,
409 public_key: &PublicKey,
410 secret: &SecretKey,
411 data: Bytes,
412 ) -> VeilidAPIResult<Signature> {
413 let cs = self.guard.clone_arc();
414 let public_key = public_key.clone();
415 let secret = secret.clone();
416 cpu_yielding(move || cs.sign(&public_key, &secret, &data)).await
417 }
418
419 /// Sign the bytes in `range` and write the signature into `data` at `sig_idx`, returning the buffer.
420 ///
421 /// Local CPU only, offloaded to the rayon thread pool off-WASM.
422 ///
423 /// Errors `VeilidAPIError::Generic` if `public_key` or `secret` has the wrong kind or length,
424 /// `VeilidAPIError::ParseError` if they do not form a valid ed25519 keypair or `sig_idx` is out
425 /// of bounds, `VeilidAPIError::InvalidArgument` if `range` is out of bounds,
426 /// `VeilidAPIError::Internal` if signing fails.
427 pub async fn sign_in_place(
428 &self,
429 public_key: &PublicKey,
430 secret: &SecretKey,
431 mut data: BytesMut,
432 range: Range<usize>,
433 sig_idx: usize,
434 ) -> VeilidAPIResult<BytesMut> {
435 let cs = self.guard.clone_arc();
436 let public_key = public_key.clone();
437 let secret = secret.clone();
438 cpu_yielding(move || {
439 cs.sign_in_place(&public_key, &secret, &mut data, range, sig_idx)?;
440 Ok(data)
441 })
442 .await
443 }
444
445 /// Verify a detached signature over a buffer against a public key.
446 ///
447 /// Local CPU only, offloaded to the rayon thread pool off-WASM.
448 ///
449 /// Returns `Ok(false)` if the signature does not match. Errors `VeilidAPIError::Generic` if
450 /// `public_key` or `signature` has the wrong kind or length, `VeilidAPIError::ParseError` if
451 /// `public_key` is not a valid ed25519 point.
452 pub async fn verify(
453 &self,
454 public_key: &PublicKey,
455 data: Bytes,
456 signature: &Signature,
457 ) -> VeilidAPIResult<bool> {
458 let cs = self.guard.clone_arc();
459 let public_key = public_key.clone();
460 let signature = signature.clone();
461 cpu_yielding(move || cs.verify(&public_key, &data, &signature)).await
462 }
463
464 /// Verify the signature at `sig_idx` over the bytes in `range` of `data` against a public key.
465 ///
466 /// Local CPU only, offloaded to the rayon thread pool off-WASM.
467 ///
468 /// Returns `Ok(false)` if the signature does not match. Errors `VeilidAPIError::Generic` if
469 /// `public_key` has the wrong kind or length, `VeilidAPIError::ParseError` if `public_key` is
470 /// not a valid ed25519 point, `VeilidAPIError::Internal` if `range` or `sig_idx` is out of bounds.
471 pub async fn verify_in_place(
472 &self,
473 public_key: &PublicKey,
474 data: Bytes,
475 range: Range<usize>,
476 sig_idx: usize,
477 ) -> VeilidAPIResult<bool> {
478 let cs = self.guard.clone_arc();
479 let public_key = public_key.clone();
480 cpu_yielding(move || cs.verify_in_place(&public_key, &data, range, sig_idx)).await
481 }
482
483 // AEAD Encrypt/Decrypt
484
485 /// Decrypt and authenticate an AEAD ciphertext into a new buffer.
486 ///
487 /// Local CPU only; offloaded to the rayon thread pool off-WASM once the buffer exceeds the scaling
488 /// threshold, else run inline.
489 ///
490 /// Errors `VeilidAPIError::Generic` if `nonce` or `shared_secret` has the wrong kind or length,
491 /// or if authentication fails (tampered ciphertext, wrong key/nonce, or mismatched
492 /// `associated_data`); `VeilidAPIError::Internal` on an internal length conversion failure.
493 pub async fn decrypt_aead(
494 &self,
495 body: Bytes,
496 nonce: &Nonce,
497 shared_secret: &SharedSecret,
498 associated_data: Option<Bytes>,
499 ) -> VeilidAPIResult<Bytes> {
500 let cs = self.guard.clone_arc();
501 let nonce = nonce.clone();
502 let shared_secret = shared_secret.clone();
503 scaled_yielding(body.len(), 1024, 8192, move || {
504 Ok(cs
505 .decrypt_aead(&body, &nonce, &shared_secret, associated_data.as_deref())?
506 .into())
507 })
508 .await
509 }
510 /// Decrypt and authenticate an AEAD ciphertext in place, returning the truncated plaintext buffer.
511 ///
512 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
513 ///
514 /// Errors `VeilidAPIError::Generic` if `shared_secret` has the wrong kind or length, or if
515 /// authentication fails (tampered ciphertext, wrong key/nonce, or mismatched `associated_data`);
516 /// `VeilidAPIError::Internal` on an internal length conversion failure.
517 pub async fn decrypt_in_place_aead(
518 &self,
519 mut body: BytesMut,
520 nonce: &Nonce,
521 shared_secret: &SharedSecret,
522 associated_data: Option<Bytes>,
523 ) -> VeilidAPIResult<BytesMut> {
524 let cs = self.guard.clone_arc();
525 let nonce = nonce.clone();
526 let shared_secret = shared_secret.clone();
527 scaled_yielding(body.len(), 1024, 8192, move || {
528 cs.decrypt_in_place_aead(
529 &mut body,
530 &nonce,
531 &shared_secret,
532 associated_data.as_deref(),
533 )?;
534
535 Ok(body)
536 })
537 .await
538 }
539
540 /// Encrypt and authenticate a buffer with AEAD into a new ciphertext.
541 ///
542 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
543 ///
544 /// Errors `VeilidAPIError::Generic` if `nonce` or `shared_secret` has the wrong kind or length;
545 /// `VeilidAPIError::Internal` on an internal length conversion failure.
546 pub async fn encrypt_aead(
547 &self,
548 body: Bytes,
549 nonce: &Nonce,
550 shared_secret: &SharedSecret,
551 associated_data: Option<Bytes>,
552 ) -> VeilidAPIResult<Bytes> {
553 let cs = self.guard.clone_arc();
554 let nonce = nonce.clone();
555 let shared_secret = shared_secret.clone();
556 scaled_yielding(body.len(), 1024, 8192, move || {
557 Ok(cs
558 .encrypt_aead(&body, &nonce, &shared_secret, associated_data.as_deref())?
559 .into())
560 })
561 .await
562 }
563
564 /// Encrypt and authenticate a buffer with AEAD in place, appending the authentication tag.
565 ///
566 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
567 ///
568 /// Errors `VeilidAPIError::Generic` if `nonce` or `shared_secret` has the wrong kind or length;
569 /// `VeilidAPIError::Internal` on an internal length conversion failure.
570 pub async fn encrypt_in_place_aead(
571 &self,
572 mut body: BytesMut,
573 nonce: &Nonce,
574 shared_secret: &SharedSecret,
575 associated_data: Option<Bytes>,
576 ) -> VeilidAPIResult<BytesMut> {
577 let cs = self.guard.clone_arc();
578 let nonce = nonce.clone();
579 let shared_secret = shared_secret.clone();
580 scaled_yielding(body.len(), 1024, 8192, move || {
581 cs.encrypt_in_place_aead(
582 &mut body,
583 &nonce,
584 &shared_secret,
585 associated_data.as_deref(),
586 )?;
587
588 Ok(body)
589 })
590 .await
591 }
592
593 // NoAuth Encrypt/Decrypt
594
595 /// Unauthenticated buffer-to-buffer crypt: transform `in_buf` into `out_buf` starting at `out_idx`.
596 ///
597 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
598 ///
599 /// Errors `VeilidAPIError::Generic` if `nonce` or `shared_secret` has the wrong kind or length;
600 /// `VeilidAPIError::Internal` on an internal length conversion failure.
601 pub async fn crypt_b2b_no_auth(
602 &self,
603 in_buf: Bytes,
604 mut out_buf: BytesMut,
605 out_idx: usize,
606 nonce: &Nonce,
607 shared_secret: &SharedSecret,
608 ) -> VeilidAPIResult<BytesMut> {
609 let cs = self.guard.clone_arc();
610 let nonce = nonce.clone();
611 let shared_secret = shared_secret.clone();
612 scaled_yielding(in_buf.len(), 1024, 8192, move || {
613 cs.crypt_b2b_no_auth(
614 &in_buf,
615 &mut out_buf[out_idx..out_idx + in_buf.len()],
616 &nonce,
617 &shared_secret,
618 )?;
619 Ok(out_buf)
620 })
621 .await
622 }
623
624 /// Unauthenticated in-place crypt of the bytes in `range`.
625 ///
626 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
627 ///
628 /// Errors `VeilidAPIError::Internal` if `range` is out of bounds, `VeilidAPIError::Generic` if
629 /// `nonce` or `shared_secret` has the wrong kind or length.
630 pub async fn crypt_in_place_no_auth(
631 &self,
632 mut body: BytesMut,
633 range: Range<usize>,
634 nonce: &Nonce,
635 shared_secret: &SharedSecret,
636 ) -> VeilidAPIResult<BytesMut> {
637 let cs = self.guard.clone_arc();
638 let nonce = nonce.clone();
639 let shared_secret = shared_secret.clone();
640 scaled_yielding(body.len(), 1024, 8192, move || {
641 cs.crypt_in_place_no_auth(
642 body.as_mut()
643 .get_mut(range)
644 .ok_or_else(|| VeilidAPIError::internal("range is out of bounds"))?,
645 &nonce,
646 &shared_secret,
647 )?;
648 Ok(body)
649 })
650 .await
651 }
652
653 /// Unauthenticated crypt into a fresh 8-byte-aligned output buffer.
654 ///
655 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
656 ///
657 /// Errors `VeilidAPIError::Generic` if `nonce` or `shared_secret` has the wrong kind or length;
658 /// `VeilidAPIError::Internal` on an internal length conversion failure.
659 pub async fn crypt_no_auth_aligned_8(
660 &self,
661 body: Bytes,
662 nonce: &Nonce,
663 shared_secret: &SharedSecret,
664 ) -> VeilidAPIResult<Vec<u8>> {
665 let cs = self.guard.clone_arc();
666 let nonce = nonce.clone();
667 let shared_secret = shared_secret.clone();
668 scaled_yielding(body.len(), 1024, 8192, move || {
669 cs.crypt_no_auth_aligned_8(&body, &nonce, &shared_secret)
670 })
671 .await
672 }
673
674 /// Unauthenticated crypt into a fresh unaligned output buffer.
675 ///
676 /// Local CPU only; offloaded to the rayon thread pool off-WASM for large buffers, else run inline.
677 ///
678 /// Errors `VeilidAPIError::Generic` if `nonce` or `shared_secret` has the wrong kind or length;
679 /// `VeilidAPIError::Internal` on an internal length conversion failure.
680 pub async fn crypt_no_auth_unaligned(
681 &self,
682 body: Bytes,
683 nonce: &Nonce,
684 shared_secret: &SharedSecret,
685 ) -> VeilidAPIResult<Vec<u8>> {
686 let cs = self.guard.clone_arc();
687 let nonce = nonce.clone();
688 let shared_secret = shared_secret.clone();
689 scaled_yielding(body.len(), 1024, 8192, move || {
690 cs.crypt_no_auth_unaligned(&body, &nonce, &shared_secret)
691 })
692 .await
693 }
694}