noxtls_psa/provider.rs
1// Copyright (c) 2019-2026, Argenox Technologies LLC
2// All rights reserved.
3//
4// SPDX-License-Identifier: GPL-2.0-only OR LicenseRef-Argenox-Commercial-License
5//
6// This file is part of the NoxTLS Library.
7//
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by the
10// Free Software Foundation; version 2 of the License.
11//
12// Alternatively, this file may be used under the terms of a commercial
13// license from Argenox Technologies LLC.
14//
15// See `noxtls/LICENSE` and `noxtls/LICENSE.md` in this repository for full details.
16// CONTACT: info@argenox.com
17
18#[cfg(feature = "alloc")]
19use alloc::{collections::BTreeMap, vec::Vec};
20use noxtls_core::{Error, Result};
21use noxtls_crypto::{
22 noxtls_aes_gcm_encrypt, noxtls_p256_ecdh_shared_secret, noxtls_p256_ecdsa_sign_sha256,
23 noxtls_rsaes_oaep_sha256_decrypt, noxtls_rsaes_pkcs1_v15_decrypt,
24 noxtls_rsassa_pss_sha256_sign, noxtls_rsassa_sha256_sign, noxtls_sha256, noxtls_x25519,
25 AesCipher, P256PrivateKey, P256PublicKey, RsaPrivateKey,
26};
27
28/// Identifies a backend-managed external key object.
29#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
30pub struct PsaExternalKeyHandle {
31 id: Vec<u8>,
32}
33
34impl PsaExternalKeyHandle {
35 /// Constructs an external key handle from opaque identifier bytes.
36 ///
37 /// # Arguments
38 ///
39 /// * `id` - Opaque provider-owned key identifier bytes.
40 ///
41 /// # Returns
42 ///
43 /// A noxtls_new [`PsaExternalKeyHandle`] owning the identifier bytes.
44 pub fn noxtls_new(id: Vec<u8>) -> Self {
45 Self { id }
46 }
47
48 /// Borrows the opaque key identifier bytes.
49 ///
50 /// # Arguments
51 ///
52 /// * `self` - Handle whose stable identifier bytes are required.
53 ///
54 /// # Returns
55 ///
56 /// Borrowed opaque bytes identifying the provider key object.
57 pub fn as_bytes(&self) -> &[u8] {
58 &self.id
59 }
60}
61
62/// Enumerates signing algorithms supported by PSA provider mappings.
63#[derive(Copy, Clone, Debug, Eq, PartialEq)]
64pub enum PsaSignAlgorithm {
65 /// RSA PKCS#1 v1.5 signing with SHA-256 digest.
66 RsaPkcs1Sha256,
67 /// RSA PSS signing with SHA-256 digest.
68 RsaPssSha256,
69 /// ECDSA signing over P-256 with SHA-256 digest.
70 EcdsaP256Sha256,
71}
72
73/// Enumerates decrypt algorithms supported by PSA provider mappings.
74#[derive(Copy, Clone, Debug, Eq, PartialEq)]
75pub enum PsaDecryptAlgorithm {
76 /// RSA PKCS#1 v1.5 decryption.
77 RsaPkcs1v15,
78 /// RSA OAEP decryption using SHA-256.
79 RsaOaepSha256,
80}
81
82/// Enumerates derive algorithms supported by PSA provider mappings.
83#[derive(Copy, Clone, Debug, Eq, PartialEq)]
84pub enum PsaDeriveAlgorithm {
85 /// X25519 shared secret derivation.
86 X25519,
87 /// P-256 ECDH shared secret derivation.
88 EcdhP256,
89}
90
91/// Carries data required for backend sign operations.
92#[derive(Clone, Debug)]
93pub struct KeySignRequest<'a> {
94 /// Opaque provider handle to signing key object.
95 pub handle: &'a PsaExternalKeyHandle,
96 /// Algorithm selector for sign operation.
97 pub noxtls_algorithm: PsaSignAlgorithm,
98 /// Input message bytes to be signed.
99 pub message: &'a [u8],
100 /// Optional PSS salt bytes for algorithms requiring explicit salt.
101 pub salt: Option<&'a [u8]>,
102}
103
104/// Carries data required for backend decrypt operations.
105#[derive(Clone, Debug)]
106pub struct KeyDecryptRequest<'a> {
107 /// Opaque provider handle to decrypt key object.
108 pub handle: &'a PsaExternalKeyHandle,
109 /// Algorithm selector for decrypt operation.
110 pub noxtls_algorithm: PsaDecryptAlgorithm,
111 /// Ciphertext bytes to decrypt.
112 pub ciphertext: &'a [u8],
113 /// Optional OAEP label bytes for algorithms requiring explicit label.
114 pub label: Option<&'a [u8]>,
115}
116
117/// Carries data required for backend derive operations.
118#[derive(Clone, Debug)]
119pub struct KeyDeriveRequest<'a> {
120 /// Opaque provider handle to derive key object.
121 pub handle: &'a PsaExternalKeyHandle,
122 /// Algorithm selector for derive operation.
123 pub noxtls_algorithm: PsaDeriveAlgorithm,
124 /// Peer public-key bytes in noxtls_algorithm-expected encoding.
125 pub peer_public_key: &'a [u8],
126}
127
128/// Carries AES-GCM encrypt operation inputs.
129#[derive(Clone, Debug)]
130pub struct AeadEncryptRequest<'a> {
131 /// Symmetric encryption key bytes.
132 pub key: &'a [u8],
133 /// Nonce bytes for AES-GCM operation.
134 pub nonce: &'a [u8],
135 /// Associated authenticated data bytes.
136 pub aad: &'a [u8],
137 /// Plaintext bytes to encrypt.
138 pub plaintext: &'a [u8],
139}
140
141/// Carries AES-GCM encryption outputs.
142#[derive(Clone, Debug, Eq, PartialEq)]
143pub struct AeadEncryptResponse {
144 /// Produced ciphertext bytes.
145 pub ciphertext: Vec<u8>,
146 /// Produced 16-byte authentication tag.
147 pub tag: [u8; 16],
148}
149
150/// Defines backend operations required by PSA provider surface.
151pub trait PsaCryptoBackend {
152 /// Executes an asymmetric signing operation.
153 ///
154 /// # Arguments
155 ///
156 /// * `self` - Backend implementation receiving sign request.
157 /// * `request` - Sign request containing handle, noxtls_algorithm, and digest.
158 ///
159 /// # Returns
160 ///
161 /// Signature bytes generated by the backend.
162 ///
163 /// # Errors
164 ///
165 /// Returns [`Error`] when handle resolution, policy checks, or crypto operation fails.
166 fn sign(&self, request: &KeySignRequest<'_>) -> Result<Vec<u8>>;
167
168 /// Executes an asymmetric decrypt operation.
169 ///
170 /// # Arguments
171 ///
172 /// * `self` - Backend implementation receiving decrypt request.
173 /// * `request` - Decrypt request containing handle, noxtls_algorithm, and ciphertext.
174 ///
175 /// # Returns
176 ///
177 /// Plaintext bytes on successful decrypt.
178 ///
179 /// # Errors
180 ///
181 /// Returns [`Error`] when handle resolution, policy checks, or crypto operation fails.
182 fn decrypt(&self, request: &KeyDecryptRequest<'_>) -> Result<Vec<u8>>;
183
184 /// Executes a key-agreement derive operation.
185 ///
186 /// # Arguments
187 ///
188 /// * `self` - Backend implementation receiving derive request.
189 /// * `request` - Derive request containing handle, noxtls_algorithm, and peer key.
190 ///
191 /// # Returns
192 ///
193 /// Shared secret bytes for the selected derive noxtls_algorithm.
194 ///
195 /// # Errors
196 ///
197 /// Returns [`Error`] when handle resolution, policy checks, or derive operation fails.
198 fn noxtls_derive(&self, request: &KeyDeriveRequest<'_>) -> Result<Vec<u8>>;
199
200 /// Fills output bytes with random data.
201 ///
202 /// # Arguments
203 ///
204 /// * `self` - Backend implementation receiving random request.
205 /// * `out` - Mutable output buffer for random bytes.
206 ///
207 /// # Returns
208 ///
209 /// `Ok(())` when the output buffer is fully written.
210 ///
211 /// # Errors
212 ///
213 /// Returns [`Error`] when backend cannot provide entropy.
214 fn random(&self, out: &mut [u8]) -> Result<()>;
215
216 /// Computes a SHA-256 digest.
217 ///
218 /// # Arguments
219 ///
220 /// * `self` - Backend implementation receiving hash request.
221 /// * `input` - Bytes to hash.
222 ///
223 /// # Returns
224 ///
225 /// A 32-byte SHA-256 digest.
226 ///
227 /// # Errors
228 ///
229 /// Returns [`Error`] when hashing fails for the backend.
230 fn noxtls_sha256(&self, input: &[u8]) -> Result<[u8; 32]>;
231
232 /// Encrypts plaintext with AES-GCM.
233 ///
234 /// # Arguments
235 ///
236 /// * `self` - Backend implementation receiving AEAD request.
237 /// * `request` - AES-GCM request with key, nonce, AAD, and plaintext.
238 ///
239 /// # Returns
240 ///
241 /// Ciphertext bytes plus a 16-byte authentication tag.
242 ///
243 /// # Errors
244 ///
245 /// Returns [`Error`] when backend lacks AES-GCM support or encryption fails.
246 fn noxtls_aes_gcm_encrypt(
247 &self,
248 request: &AeadEncryptRequest<'_>,
249 ) -> Result<AeadEncryptResponse>;
250}
251
252/// Adapts a concrete backend into a stable PSA provider API.
253#[derive(Clone, Debug)]
254pub struct PsaProvider<B> {
255 backend: B,
256}
257
258impl<B> PsaProvider<B> {
259 /// Constructs a provider from a concrete backend implementation.
260 ///
261 /// # Arguments
262 ///
263 /// * `backend` - Backend implementation used by provider operations.
264 ///
265 /// # Returns
266 ///
267 /// A noxtls_new [`PsaProvider`] owning the backend.
268 pub fn noxtls_new(backend: B) -> Self {
269 Self { backend }
270 }
271}
272
273impl<B: PsaCryptoBackend> PsaProvider<B> {
274 /// Dispatches signing requests to the configured backend.
275 ///
276 /// # Arguments
277 ///
278 /// * `self` - Provider dispatching to backend.
279 /// * `request` - Signing request to execute.
280 ///
281 /// # Returns
282 ///
283 /// Signature bytes produced by backend.
284 ///
285 /// # Errors
286 ///
287 /// Returns backend-provided [`Error`] on failures.
288 pub fn sign(&self, request: &KeySignRequest<'_>) -> Result<Vec<u8>> {
289 self.backend.sign(request)
290 }
291
292 /// Dispatches decrypt requests with uniform decrypt failure posture.
293 ///
294 /// # Arguments
295 ///
296 /// * `self` - Provider dispatching to backend.
297 /// * `request` - Decrypt request to execute.
298 ///
299 /// # Returns
300 ///
301 /// Plaintext bytes returned by backend.
302 ///
303 /// # Errors
304 ///
305 /// Returns [`Error::CryptoFailure`] for decrypt failures to avoid oracle leakage.
306 pub fn decrypt(&self, request: &KeyDecryptRequest<'_>) -> Result<Vec<u8>> {
307 self.backend
308 .decrypt(request)
309 .map_err(|_| Error::CryptoFailure("psa cryptographic operation failed"))
310 }
311
312 /// Dispatches derive requests to the configured backend.
313 ///
314 /// # Arguments
315 ///
316 /// * `self` - Provider dispatching to backend.
317 /// * `request` - Derive request to execute.
318 ///
319 /// # Returns
320 ///
321 /// Shared secret bytes produced by backend.
322 ///
323 /// # Errors
324 ///
325 /// Returns backend-provided [`Error`] on failures.
326 pub fn noxtls_derive(&self, request: &KeyDeriveRequest<'_>) -> Result<Vec<u8>> {
327 self.backend.noxtls_derive(request)
328 }
329
330 /// Fills output bytes with backend-provided random data.
331 ///
332 /// # Arguments
333 ///
334 /// * `self` - Provider dispatching to backend.
335 /// * `out` - Mutable output buffer to fill.
336 ///
337 /// # Returns
338 ///
339 /// `Ok(())` when random output was written to the caller buffer.
340 ///
341 /// # Errors
342 ///
343 /// Returns backend-provided [`Error`] when random generation fails.
344 pub fn random(&self, out: &mut [u8]) -> Result<()> {
345 self.backend.random(out)
346 }
347
348 /// Computes SHA-256 using backend digest implementation.
349 ///
350 /// # Arguments
351 ///
352 /// * `self` - Provider dispatching to backend.
353 /// * `input` - Bytes to hash.
354 ///
355 /// # Returns
356 ///
357 /// 32-byte SHA-256 digest bytes.
358 ///
359 /// # Errors
360 ///
361 /// Returns backend-provided [`Error`] on hashing failures.
362 pub fn noxtls_sha256(&self, input: &[u8]) -> Result<[u8; 32]> {
363 self.backend.noxtls_sha256(input)
364 }
365
366 /// Encrypts plaintext with backend AES-GCM implementation.
367 ///
368 /// # Arguments
369 ///
370 /// * `self` - Provider dispatching to backend.
371 /// * `request` - AES-GCM request with key/nonce/aad/plaintext.
372 ///
373 /// # Returns
374 ///
375 /// Ciphertext bytes plus a 16-byte authentication tag.
376 ///
377 /// # Errors
378 ///
379 /// Returns backend-provided [`Error`] when encryption fails.
380 pub fn noxtls_aes_gcm_encrypt(
381 &self,
382 request: &AeadEncryptRequest<'_>,
383 ) -> Result<AeadEncryptResponse> {
384 self.backend.noxtls_aes_gcm_encrypt(request)
385 }
386}
387
388/// Stores policy flags for registered key handles.
389#[derive(Copy, Clone, Debug, Eq, PartialEq)]
390struct HandlePolicy {
391 allow_sign: bool,
392 allow_decrypt: bool,
393 allow_derive: bool,
394}
395
396/// Represents the private key material variants used for software-backed tests.
397#[derive(Clone, Debug)]
398enum SoftwarePrivateMaterial {
399 Rsa(RsaPrivateKey),
400 X25519([u8; 32]),
401 P256(P256PrivateKey),
402}
403
404/// Implements an in-process backend that mirrors PSA handle semantics for tests.
405#[derive(Clone, Debug, Default)]
406pub struct PsaSoftwareBackend {
407 keys: BTreeMap<Vec<u8>, (SoftwarePrivateMaterial, HandlePolicy)>,
408}
409
410impl PsaSoftwareBackend {
411 /// Constructs an empty software backend.
412 ///
413 /// # Arguments
414 ///
415 /// * `()` - This constructor has no parameters.
416 ///
417 /// # Returns
418 ///
419 /// A noxtls_new empty [`PsaSoftwareBackend`] value.
420 pub fn noxtls_new() -> Self {
421 Self {
422 keys: BTreeMap::new(),
423 }
424 }
425
426 /// Registers an RSA private key with handle-level usage policy.
427 ///
428 /// # Arguments
429 ///
430 /// * `handle` - Opaque key handle used for future operations.
431 /// * `key` - RSA private key material owned by backend.
432 /// * `allow_sign` - Whether sign operations are authorized for this handle.
433 /// * `allow_decrypt` - Whether decrypt operations are authorized for this handle.
434 ///
435 /// # Returns
436 ///
437 /// `Ok(())` after key registration succeeds.
438 ///
439 /// # Errors
440 ///
441 /// Returns [`Error::PolicyViolation`] if the handle is already registered.
442 pub fn register_rsa_key(
443 &mut self,
444 handle: PsaExternalKeyHandle,
445 key: RsaPrivateKey,
446 allow_sign: bool,
447 allow_decrypt: bool,
448 ) -> Result<()> {
449 self.insert_key(
450 handle,
451 SoftwarePrivateMaterial::Rsa(key),
452 HandlePolicy {
453 allow_sign,
454 allow_decrypt,
455 allow_derive: false,
456 },
457 )
458 }
459
460 /// Registers an X25519 private key with derive-policy controls.
461 ///
462 /// # Arguments
463 ///
464 /// * `handle` - Opaque key handle used for future derive operations.
465 /// * `key` - X25519 private scalar bytes.
466 /// * `allow_derive` - Whether derive operations are authorized for this handle.
467 ///
468 /// # Returns
469 ///
470 /// `Ok(())` after key registration succeeds.
471 ///
472 /// # Errors
473 ///
474 /// Returns [`Error::PolicyViolation`] if the handle is already registered.
475 pub fn register_x25519_key(
476 &mut self,
477 handle: PsaExternalKeyHandle,
478 key: [u8; 32],
479 allow_derive: bool,
480 ) -> Result<()> {
481 self.insert_key(
482 handle,
483 SoftwarePrivateMaterial::X25519(key),
484 HandlePolicy {
485 allow_sign: false,
486 allow_decrypt: false,
487 allow_derive,
488 },
489 )
490 }
491
492 /// Registers a P-256 private key with derive/sign policy controls.
493 ///
494 /// # Arguments
495 ///
496 /// * `handle` - Opaque key handle used for future operations.
497 /// * `key` - P-256 private key material.
498 /// * `allow_sign` - Whether sign operations are authorized for this handle.
499 /// * `allow_derive` - Whether derive operations are authorized for this handle.
500 ///
501 /// # Returns
502 ///
503 /// `Ok(())` after key registration succeeds.
504 ///
505 /// # Errors
506 ///
507 /// Returns [`Error::StateError`] if the handle is already registered.
508 pub fn register_p256_key(
509 &mut self,
510 handle: PsaExternalKeyHandle,
511 key: P256PrivateKey,
512 allow_sign: bool,
513 allow_derive: bool,
514 ) -> Result<()> {
515 self.insert_key(
516 handle,
517 SoftwarePrivateMaterial::P256(key),
518 HandlePolicy {
519 allow_sign,
520 allow_decrypt: false,
521 allow_derive,
522 },
523 )
524 }
525
526 /// Inserts a key record while enforcing unique handle ownership.
527 ///
528 /// # Arguments
529 ///
530 /// * `handle` - Opaque key handle used as map key.
531 /// * `material` - Private material variant to store.
532 /// * `policy` - Allowed operation policy for this handle.
533 ///
534 /// # Returns
535 ///
536 /// `Ok(())` when the record is inserted.
537 ///
538 /// # Errors
539 ///
540 /// Returns [`Error::PolicyViolation`] when handle already exists.
541 fn insert_key(
542 &mut self,
543 handle: PsaExternalKeyHandle,
544 material: SoftwarePrivateMaterial,
545 policy: HandlePolicy,
546 ) -> Result<()> {
547 if self.keys.contains_key(handle.as_bytes()) {
548 return Err(Error::StateError("psa key handle already registered"));
549 }
550 self.keys.insert(handle.id, (material, policy));
551 Ok(())
552 }
553
554 /// Resolves a key record and policy by handle identifier.
555 ///
556 /// # Arguments
557 ///
558 /// * `handle` - Opaque handle whose key material is required.
559 ///
560 /// # Returns
561 ///
562 /// Borrowed private material and policy tuple for the handle.
563 ///
564 /// # Errors
565 ///
566 /// Returns [`Error::PolicyViolation`] when the handle is unknown.
567 fn resolve_key(
568 &self,
569 handle: &PsaExternalKeyHandle,
570 ) -> Result<&(SoftwarePrivateMaterial, HandlePolicy)> {
571 self.keys
572 .get(handle.as_bytes())
573 .ok_or(Error::StateError("psa key handle invalid"))
574 }
575}
576
577impl PsaCryptoBackend for PsaSoftwareBackend {
578 /// Executes signing operations using software cryptographic primitives.
579 ///
580 /// # Arguments
581 ///
582 /// * `self` - Software backend state containing registered keys.
583 /// * `request` - Sign request with handle, noxtls_algorithm, and digest.
584 ///
585 /// # Returns
586 ///
587 /// Signature bytes from RSA sign operations.
588 ///
589 /// # Errors
590 ///
591 /// Returns policy or crypto errors for unknown handles, denied usage, or bad key type.
592 fn sign(&self, request: &KeySignRequest<'_>) -> Result<Vec<u8>> {
593 let (material, policy) = self.resolve_key(request.handle)?;
594 if !policy.allow_sign {
595 return Err(Error::StateError("psa sign not permitted by key policy"));
596 }
597 match (request.noxtls_algorithm, material) {
598 (PsaSignAlgorithm::RsaPkcs1Sha256, SoftwarePrivateMaterial::Rsa(key)) => {
599 noxtls_rsassa_sha256_sign(key, request.message)
600 }
601 (PsaSignAlgorithm::RsaPssSha256, SoftwarePrivateMaterial::Rsa(key)) => {
602 let salt = request.salt.ok_or(Error::InvalidLength(
603 "rsa-pss-sha256 signing requires a salt",
604 ))?;
605 noxtls_rsassa_pss_sha256_sign(key, request.message, salt)
606 }
607 (PsaSignAlgorithm::EcdsaP256Sha256, SoftwarePrivateMaterial::P256(key)) => {
608 let (r, s) = noxtls_p256_ecdsa_sign_sha256(key, request.message)?;
609 let mut signature = Vec::with_capacity(64);
610 signature.extend_from_slice(&r);
611 signature.extend_from_slice(&s);
612 Ok(signature)
613 }
614 _ => Err(Error::UnsupportedFeature(
615 "psa sign noxtls_algorithm/key mismatch",
616 )),
617 }
618 }
619
620 /// Executes decrypt operations using software cryptographic primitives.
621 ///
622 /// # Arguments
623 ///
624 /// * `self` - Software backend state containing registered keys.
625 /// * `request` - Decrypt request with handle, noxtls_algorithm, and ciphertext.
626 ///
627 /// # Returns
628 ///
629 /// Plaintext bytes decrypted from input ciphertext.
630 ///
631 /// # Errors
632 ///
633 /// Returns policy or crypto errors for unknown handles, denied usage, or bad key type.
634 fn decrypt(&self, request: &KeyDecryptRequest<'_>) -> Result<Vec<u8>> {
635 let (material, policy) = self.resolve_key(request.handle)?;
636 if !policy.allow_decrypt {
637 return Err(Error::StateError("psa decrypt not permitted by key policy"));
638 }
639 match (request.noxtls_algorithm, material) {
640 (PsaDecryptAlgorithm::RsaPkcs1v15, SoftwarePrivateMaterial::Rsa(key)) => {
641 noxtls_rsaes_pkcs1_v15_decrypt(key, request.ciphertext)
642 }
643 (PsaDecryptAlgorithm::RsaOaepSha256, SoftwarePrivateMaterial::Rsa(key)) => {
644 noxtls_rsaes_oaep_sha256_decrypt(
645 key,
646 request.ciphertext,
647 request.label.unwrap_or(&[]),
648 )
649 }
650 _ => Err(Error::UnsupportedFeature(
651 "psa decrypt noxtls_algorithm/key mismatch",
652 )),
653 }
654 }
655
656 /// Executes derive operations using software X25519 primitive.
657 ///
658 /// # Arguments
659 ///
660 /// * `self` - Software backend state containing registered keys.
661 /// * `request` - Derive request with handle, noxtls_algorithm, and peer key.
662 ///
663 /// # Returns
664 ///
665 /// Shared secret bytes from X25519 derive operation.
666 ///
667 /// # Errors
668 ///
669 /// Returns policy or parse errors for unknown handles, denied usage, or invalid peer key.
670 fn noxtls_derive(&self, request: &KeyDeriveRequest<'_>) -> Result<Vec<u8>> {
671 let (material, policy) = self.resolve_key(request.handle)?;
672 if !policy.allow_derive {
673 return Err(Error::StateError("psa derive not permitted by key policy"));
674 }
675 match (request.noxtls_algorithm, material) {
676 (PsaDeriveAlgorithm::X25519, SoftwarePrivateMaterial::X25519(private)) => {
677 if request.peer_public_key.len() != 32 {
678 return Err(Error::ParseFailure("x25519 peer public key length invalid"));
679 }
680 let mut peer = [0u8; 32];
681 peer.copy_from_slice(request.peer_public_key);
682 Ok(noxtls_x25519(private, &peer).to_vec())
683 }
684 (PsaDeriveAlgorithm::EcdhP256, SoftwarePrivateMaterial::P256(private)) => {
685 let peer = P256PublicKey::from_uncompressed(request.peer_public_key)?;
686 Ok(noxtls_p256_ecdh_shared_secret(private, &peer)?.to_vec())
687 }
688 _ => Err(Error::UnsupportedFeature(
689 "psa derive noxtls_algorithm/key mismatch",
690 )),
691 }
692 }
693
694 /// Produces deterministic random bytes for validation-only posture.
695 ///
696 /// # Arguments
697 ///
698 /// * `self` - Software backend state (not used by this implementation).
699 /// * `out` - Mutable output buffer to fill with deterministic bytes.
700 ///
701 /// # Returns
702 ///
703 /// `Ok(())` once all output bytes are filled.
704 ///
705 /// # Errors
706 ///
707 /// This function does not return errors in the software backend.
708 fn random(&self, out: &mut [u8]) -> Result<()> {
709 for (idx, byte) in out.iter_mut().enumerate() {
710 *byte = (idx as u8).wrapping_mul(17).wrapping_add(0x5A);
711 }
712 Ok(())
713 }
714
715 /// Computes SHA-256 digest with software primitive implementation.
716 ///
717 /// # Arguments
718 ///
719 /// * `self` - Software backend state (not used by this implementation).
720 /// * `input` - Input bytes to hash.
721 ///
722 /// # Returns
723 ///
724 /// 32-byte SHA-256 digest.
725 ///
726 /// # Errors
727 ///
728 /// Returns crypto error if digest primitive reports a failure.
729 fn noxtls_sha256(&self, input: &[u8]) -> Result<[u8; 32]> {
730 Ok(noxtls_sha256(input))
731 }
732
733 /// Encrypts using AES-GCM software primitive.
734 ///
735 /// # Arguments
736 ///
737 /// * `self` - Software backend state (not used by this implementation).
738 /// * `request` - Encryption request with key, nonce, AAD, and plaintext.
739 ///
740 /// # Returns
741 ///
742 /// Ciphertext bytes plus 16-byte authentication tag.
743 ///
744 /// # Errors
745 ///
746 /// Returns [`Error::UnsupportedFeature`] because software AES-GCM path is not wired here.
747 fn noxtls_aes_gcm_encrypt(
748 &self,
749 request: &AeadEncryptRequest<'_>,
750 ) -> Result<AeadEncryptResponse> {
751 let cipher = AesCipher::noxtls_new(request.key)?;
752 let (ciphertext, tag) =
753 noxtls_aes_gcm_encrypt(&cipher, request.nonce, request.aad, request.plaintext)?;
754 Ok(AeadEncryptResponse { ciphertext, tag })
755 }
756}
757
758/// Type alias for default software-backed PSA provider.
759pub type PsaSoftwareProvider = PsaProvider<PsaSoftwareBackend>;