Skip to main content

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