Skip to main content

psa_crypto/types/
algorithm.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4//! # PSA Algorithms
5
6#![allow(deprecated)]
7
8#[cfg(feature = "interface")]
9use crate::types::status::{Error, Result};
10#[cfg(feature = "interface")]
11use core::convert::{TryFrom, TryInto};
12#[cfg(feature = "interface")]
13use log::error;
14use serde::{Deserialize, Serialize};
15use zeroize::Zeroize;
16
17/// Enumeration of possible algorithm definitions.
18/// Each variant of the enum contains a main algorithm type (which is required for
19/// that variant).
20#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
21pub enum Algorithm {
22    /// An invalid algorithm identifier value.
23    /// `None` does not allow any cryptographic operation with the key. The key can still be
24    /// used for non-cryptographic actions such as exporting, if permitted by the usage flags.
25    None,
26    /// Hash algorithm.
27    Hash(Hash),
28    /// MAC algorithm.
29    Mac(Mac),
30    /// Symmetric Cipher algorithm.
31    Cipher(Cipher),
32    /// Authenticated Encryption with Associated Data (AEAD) algorithm.
33    Aead(Aead),
34    /// Public-key signature algorithm.
35    AsymmetricSignature(AsymmetricSignature),
36    /// Public-key encryption algorithm.
37    AsymmetricEncryption(AsymmetricEncryption),
38    /// Key agreement algorithm.
39    KeyAgreement(KeyAgreement),
40    /// Key derivation algorithm.
41    KeyDerivation(KeyDerivation),
42}
43
44impl Algorithm {
45    /// Check if the algorithm is a HMAC algorithm, truncated or not
46    ///
47    /// # Example
48    ///
49    /// ```
50    /// use psa_crypto::types::algorithm::{Algorithm, Mac, FullLengthMac, Hash};
51    /// let hmac = Algorithm::Mac(Mac::Truncated {
52    ///     mac_alg: FullLengthMac::Hmac { hash_alg: Hash::Sha256 },
53    ///     mac_length: 30,
54    /// });
55    /// assert!(hmac.is_hmac());
56    /// ```
57    pub fn is_hmac(self) -> bool {
58        match self {
59            Algorithm::Mac(mac_alg) => mac_alg.is_hmac(),
60            _ => false,
61        }
62    }
63}
64
65/// Enumeration of hash algorithms supported.
66#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
67#[allow(deprecated)]
68pub enum Hash {
69    /// MD2
70    #[deprecated = "The MD2 hash is weak and deprecated and is only recommended for use in legacy protocols."]
71    Md2,
72    /// MD4
73    #[deprecated = "The MD4 hash is weak and deprecated and is only recommended for use in legacy protocols."]
74    Md4,
75    /// MD5
76    #[deprecated = "The MD5 hash is weak and deprecated and is only recommended for use in legacy protocols."]
77    Md5,
78    /// RIPEMD-160
79    Ripemd160,
80    /// SHA-1
81    #[deprecated = "The SHA-1 hash is weak and deprecated and is only recommended for use in legacy protocols."]
82    Sha1,
83    /// SHA-224
84    Sha224,
85    /// SHA-256
86    Sha256,
87    /// SHA-384
88    Sha384,
89    /// SHA-512
90    Sha512,
91    /// SHA-512/224
92    Sha512_224,
93    /// SHA-512/256
94    Sha512_256,
95    /// SHA3-224
96    Sha3_224,
97    /// SHA3-256
98    Sha3_256,
99    /// SHA3-384
100    Sha3_384,
101    /// SHA3-512
102    Sha3_512,
103}
104
105impl Hash {
106    /// Get the digest size output by the hash algorithm in bytes
107    ///
108    /// # Example
109    ///
110    /// ```
111    /// use psa_crypto::types::algorithm::Hash;
112    /// assert_eq!(Hash::Sha256.hash_length(), 32);
113    /// assert_eq!(Hash::Sha512.hash_length(), 64);
114    /// ```
115    pub fn hash_length(self) -> usize {
116        match self {
117            Hash::Md2 | Hash::Md4 | Hash::Md5 => 16,
118            Hash::Ripemd160 | Hash::Sha1 => 20,
119            Hash::Sha224 | Hash::Sha512_224 | Hash::Sha3_224 => 28,
120            Hash::Sha256 | Hash::Sha512_256 | Hash::Sha3_256 => 32,
121            Hash::Sha384 | Hash::Sha3_384 => 48,
122            Hash::Sha3_512 | Hash::Sha512 => 64,
123        }
124    }
125}
126
127/// Enumeration of untruncated MAC algorithms.
128#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
129pub enum FullLengthMac {
130    /// HMAC algorithm
131    Hmac {
132        /// Hash algorithm to use.
133        hash_alg: Hash,
134    },
135    /// The CBC-MAC construction over a block cipher.
136    CbcMac,
137    /// The CMAC construction over a block cipher.
138    Cmac,
139}
140
141/// Enumeration of message authentication code algorithms supported.
142#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
143pub enum Mac {
144    /// Untruncated MAC algorithm
145    FullLength(FullLengthMac),
146    /// Truncated MAC algorithm
147    Truncated {
148        /// The MAC algorithm to truncate.
149        mac_alg: FullLengthMac,
150        /// Desired length of the truncated MAC in bytes.
151        mac_length: usize,
152    },
153}
154
155impl Mac {
156    /// Check if the MAC algorithm is a HMAC algorithm, truncated or not
157    pub fn is_hmac(self) -> bool {
158        matches!(
159            self,
160            Mac::FullLength(FullLengthMac::Hmac { .. })
161                | Mac::Truncated {
162                    mac_alg: FullLengthMac::Hmac { .. },
163                    ..
164                }
165        )
166    }
167
168    /// Check if the MAC algorithm is a construction over a block cipher
169    pub fn is_block_cipher_needed(self) -> bool {
170        matches!(
171            self,
172            Mac::FullLength(FullLengthMac::CbcMac)
173                | Mac::FullLength(FullLengthMac::Cmac)
174                | Mac::Truncated {
175                    mac_alg: FullLengthMac::CbcMac,
176                    ..
177                }
178                | Mac::Truncated {
179                    mac_alg: FullLengthMac::Cmac,
180                    ..
181                }
182        )
183    }
184}
185
186/// Enumeration of symmetric encryption algorithms supported.
187#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
188pub enum Cipher {
189    /// The stream cipher mode of a stream cipher algorithm.
190    StreamCipher,
191    /// A stream cipher built using the Counter (CTR) mode of a block cipher.
192    Ctr,
193    /// A stream cipher built using the Cipher Feedback (CFB) mode of a block cipher.
194    Cfb,
195    /// A stream cipher built using the Output Feedback (OFB) mode of a block cipher.
196    Ofb,
197    /// The XTS cipher mode of a block cipher.
198    Xts,
199    /// The Electronic Code Book (ECB) mode of a block cipher, with no padding.
200    EcbNoPadding,
201    /// The Cipher Block Chaining (CBC) mode of a block cipher, with no padding.
202    CbcNoPadding,
203    /// The Cipher Block Chaining (CBC) mode of a block cipher, with PKCS#7 padding.
204    CbcPkcs7,
205}
206
207impl Cipher {
208    /// Check is the cipher algorithm is a mode of a block cipher.
209    pub fn is_block_cipher_mode(self) -> bool {
210        matches!(
211            self,
212            Cipher::Ctr
213                | Cipher::Cfb
214                | Cipher::Ofb
215                | Cipher::Xts
216                | Cipher::EcbNoPadding
217                | Cipher::CbcNoPadding
218                | Cipher::CbcPkcs7
219        )
220    }
221}
222
223#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
224/// AEAD algorithm with default length tag enumeration
225pub enum AeadWithDefaultLengthTag {
226    /// The CCM authenticated encryption algorithm.
227    Ccm,
228    /// The GCM authenticated encryption algorithm.
229    Gcm,
230    /// The Chacha20-Poly1305 AEAD algorithm.
231    Chacha20Poly1305,
232}
233
234/// Enumeration of authenticated encryption with additional data algorithms
235/// supported.
236#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
237pub enum Aead {
238    /// AEAD algorithm with a default length tag
239    AeadWithDefaultLengthTag(AeadWithDefaultLengthTag),
240    /// AEAD algorithm with a shortened tag.
241    AeadWithShortenedTag {
242        /// An AEAD algorithm.
243        aead_alg: AeadWithDefaultLengthTag,
244        /// Desired length of the authentication tag in bytes.
245        tag_length: usize,
246    },
247}
248
249impl Aead {
250    /// Check if the Aead algorithm needs a block cipher
251    pub fn is_aead_on_block_cipher(self) -> bool {
252        matches!(
253            self,
254            Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Ccm)
255                | Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Gcm)
256                | Aead::AeadWithShortenedTag {
257                    aead_alg: AeadWithDefaultLengthTag::Ccm,
258                    ..
259                }
260                | Aead::AeadWithShortenedTag {
261                    aead_alg: AeadWithDefaultLengthTag::Gcm,
262                    ..
263                }
264        )
265    }
266
267    /// Check if this AEAD algorithm is the (truncated or not) Chacha20-Poly1305 AEAD algorithm.
268    pub fn is_chacha20_poly1305_alg(self) -> bool {
269        matches!(
270            self,
271            Aead::AeadWithDefaultLengthTag(AeadWithDefaultLengthTag::Chacha20Poly1305)
272                | Aead::AeadWithShortenedTag {
273                    aead_alg: AeadWithDefaultLengthTag::Chacha20Poly1305,
274                    ..
275                }
276        )
277    }
278}
279
280/// Enumeration of hash algorithms used in "hash-and-sign" algorithms.
281#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
282pub enum SignHash {
283    /// A specific hash algorithm to choose.
284    Specific(Hash),
285    /// In a hash-and-sign algorithm policy, allow any hash algorithm. This value must not be used
286    /// to build an algorithm specification to perform an operation. It is only valid to build
287    /// policies, for signature algorithms.
288    Any,
289}
290
291impl SignHash {
292    /// Check if the alg given for a cryptographic operation is permitted to be used with this
293    /// algorithm as a policy
294    pub fn is_alg_permitted(self, alg: SignHash) -> bool {
295        if let SignHash::Specific(_) = alg {
296            if self == SignHash::Any {
297                true
298            } else {
299                self == alg
300            }
301        } else {
302            // Any is not permitted for a cryptographic operation
303            false
304        }
305    }
306}
307
308impl From<Hash> for SignHash {
309    fn from(hash: Hash) -> Self {
310        SignHash::Specific(hash)
311    }
312}
313
314/// Enumeration of asymmetric signing algorithms supported.
315#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
316pub enum AsymmetricSignature {
317    /// RSA PKCS#1 v1.5 signature with hashing.
318    RsaPkcs1v15Sign {
319        /// A hash algorithm to use.
320        hash_alg: SignHash,
321    },
322    /// Raw PKCS#1 v1.5 signature.
323    RsaPkcs1v15SignRaw,
324    /// RSA PSS signature with hashing.
325    RsaPss {
326        /// A hash algorithm to use.
327        hash_alg: SignHash,
328    },
329    /// ECDSA signature with hashing.
330    Ecdsa {
331        /// A hash algorithm to use.
332        hash_alg: SignHash,
333    },
334    /// ECDSA signature without hashing.
335    EcdsaAny,
336    /// Deterministic ECDSA signature with hashing.
337    DeterministicEcdsa {
338        /// A hash algorithm to use.
339        hash_alg: SignHash,
340    },
341}
342
343impl AsymmetricSignature {
344    /// Check if the alg given for a cryptographic operation is permitted to be used with this
345    /// algorithm as a policy
346    ///
347    /// # Example
348    ///
349    /// ```
350    /// use psa_crypto::types::algorithm::{AsymmetricSignature, SignHash, Hash};
351    /// assert!(AsymmetricSignature::RsaPkcs1v15Sign { hash_alg: SignHash::Any }
352    ///         .is_alg_permitted(AsymmetricSignature::RsaPkcs1v15Sign {
353    ///             hash_alg:  SignHash::Specific(Hash::Sha1)
354    ///         })
355    ///        );
356    /// assert!(!AsymmetricSignature::RsaPkcs1v15Sign { hash_alg: SignHash::Specific(Hash::Sha256) }
357    ///         .is_alg_permitted(AsymmetricSignature::RsaPkcs1v15Sign {
358    ///             hash_alg:  SignHash::Specific(Hash::Sha1)
359    ///         })
360    ///        );
361    /// ```
362    pub fn is_alg_permitted(self, alg: AsymmetricSignature) -> bool {
363        match self {
364            AsymmetricSignature::RsaPkcs1v15Sign {
365                hash_alg: hash_policy,
366            } => {
367                if let AsymmetricSignature::RsaPkcs1v15Sign { hash_alg } = alg {
368                    hash_policy.is_alg_permitted(hash_alg)
369                } else {
370                    false
371                }
372            }
373            AsymmetricSignature::RsaPss {
374                hash_alg: hash_policy,
375            } => {
376                if let AsymmetricSignature::RsaPss { hash_alg } = alg {
377                    hash_policy.is_alg_permitted(hash_alg)
378                } else {
379                    false
380                }
381            }
382            AsymmetricSignature::Ecdsa {
383                hash_alg: hash_policy,
384            } => {
385                if let AsymmetricSignature::Ecdsa { hash_alg } = alg {
386                    hash_policy.is_alg_permitted(hash_alg)
387                } else {
388                    false
389                }
390            }
391            AsymmetricSignature::DeterministicEcdsa {
392                hash_alg: hash_policy,
393            } => {
394                if let AsymmetricSignature::DeterministicEcdsa { hash_alg } = alg {
395                    hash_policy.is_alg_permitted(hash_alg)
396                } else {
397                    false
398                }
399            }
400            // These ones can not be wildcard algorithms
401            asymmetric_signature_alg => asymmetric_signature_alg == alg,
402        }
403    }
404
405    /// Check if this is a RSA algorithm
406    pub fn is_rsa_alg(self) -> bool {
407        matches!(
408            self,
409            AsymmetricSignature::RsaPkcs1v15Sign { .. }
410                | AsymmetricSignature::RsaPkcs1v15SignRaw
411                | AsymmetricSignature::RsaPss { .. }
412        )
413    }
414
415    /// Check if this is an ECC algorithm
416    pub fn is_ecc_alg(self) -> bool {
417        matches!(
418            self,
419            AsymmetricSignature::Ecdsa { .. }
420                | AsymmetricSignature::EcdsaAny
421                | AsymmetricSignature::DeterministicEcdsa { .. }
422        )
423    }
424
425    /// Determines if the given hash length is compatible with the asymmetric signature scheme
426    pub fn is_hash_len_permitted(self, hash_len: usize) -> bool {
427        match self {
428            AsymmetricSignature::EcdsaAny | AsymmetricSignature::RsaPkcs1v15SignRaw => true,
429            AsymmetricSignature::DeterministicEcdsa { hash_alg }
430            | AsymmetricSignature::RsaPkcs1v15Sign { hash_alg }
431            | AsymmetricSignature::Ecdsa { hash_alg }
432            | AsymmetricSignature::RsaPss { hash_alg } => {
433                if let SignHash::Specific(hash_alg) = hash_alg {
434                    hash_alg.hash_length() == hash_len
435                } else {
436                    false
437                }
438            }
439        }
440    }
441
442    /// Retrieves the specific hash that the `AsymmetricSignature` algorithm is restricted to.
443    ///
444    /// For algorithms that do not specify a hash, `None` is returned.
445    pub fn hash(self) -> Option<SignHash> {
446        match self {
447            AsymmetricSignature::EcdsaAny | AsymmetricSignature::RsaPkcs1v15SignRaw => None,
448            AsymmetricSignature::DeterministicEcdsa { hash_alg }
449            | AsymmetricSignature::RsaPkcs1v15Sign { hash_alg }
450            | AsymmetricSignature::Ecdsa { hash_alg }
451            | AsymmetricSignature::RsaPss { hash_alg } => Some(hash_alg),
452        }
453    }
454}
455
456/// Enumeration of asymmetric encryption algorithms supported.
457#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
458pub enum AsymmetricEncryption {
459    /// RSA PKCS#1 v1.5 encryption.
460    RsaPkcs1v15Crypt,
461    /// RSA OAEP encryption.
462    RsaOaep {
463        /// A hash algorithm to use.
464        hash_alg: Hash,
465    },
466}
467
468/// Key agreement algorithm enumeration.
469#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
470pub enum RawKeyAgreement {
471    /// The finite-field Diffie-Hellman (DH) key agreement algorithm.
472    Ffdh,
473    /// The elliptic curve Diffie-Hellman (ECDH) key agreement algorithm.
474    Ecdh,
475}
476
477/// Enumeration of key agreement algorithms supported.
478#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
479pub enum KeyAgreement {
480    /// Key agreement only algorithm.
481    Raw(RawKeyAgreement),
482    /// Build a combined algorithm that chains a key agreement with a key derivation.
483    WithKeyDerivation {
484        /// A key agreement algorithm.
485        ka_alg: RawKeyAgreement,
486        /// A key derivation algorithm.
487        kdf_alg: KeyDerivation,
488    },
489}
490
491/// Enumeration of key derivation functions supported.
492#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Zeroize)]
493pub enum KeyDerivation {
494    /// HKDF algorithm.
495    Hkdf {
496        /// A hash algorithm to use.
497        hash_alg: Hash,
498    },
499    /// TLS-1.2 PRF algorithm.
500    Tls12Prf {
501        /// A hash algorithm to use.
502        hash_alg: Hash,
503    },
504    /// TLS-1.2 PSK-to-MasterSecret algorithm.
505    Tls12PskToMs {
506        /// A hash algorithm to use.
507        hash_alg: Hash,
508    },
509}
510
511impl From<Hash> for Algorithm {
512    fn from(alg: Hash) -> Self {
513        Algorithm::Hash(alg)
514    }
515}
516impl From<Mac> for Algorithm {
517    fn from(alg: Mac) -> Self {
518        Algorithm::Mac(alg)
519    }
520}
521impl From<Cipher> for Algorithm {
522    fn from(alg: Cipher) -> Self {
523        Algorithm::Cipher(alg)
524    }
525}
526impl From<Aead> for Algorithm {
527    fn from(alg: Aead) -> Self {
528        Algorithm::Aead(alg)
529    }
530}
531impl From<AsymmetricSignature> for Algorithm {
532    fn from(alg: AsymmetricSignature) -> Self {
533        Algorithm::AsymmetricSignature(alg)
534    }
535}
536impl From<AsymmetricEncryption> for Algorithm {
537    fn from(alg: AsymmetricEncryption) -> Self {
538        Algorithm::AsymmetricEncryption(alg)
539    }
540}
541impl From<KeyAgreement> for Algorithm {
542    fn from(alg: KeyAgreement) -> Self {
543        Algorithm::KeyAgreement(alg)
544    }
545}
546impl From<KeyDerivation> for Algorithm {
547    fn from(alg: KeyDerivation) -> Self {
548        Algorithm::KeyDerivation(alg)
549    }
550}
551
552#[cfg(feature = "interface")]
553impl TryFrom<psa_crypto_sys::psa_algorithm_t> for Algorithm {
554    type Error = Error;
555    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
556        if alg == 0 {
557            Ok(Algorithm::None)
558        } else if psa_crypto_sys::PSA_ALG_IS_HASH(alg) {
559            let hash: Hash = alg.try_into()?;
560            Ok(hash.into())
561        } else if psa_crypto_sys::PSA_ALG_IS_MAC(alg) {
562            let mac: Mac = alg.try_into()?;
563            Ok(mac.into())
564        } else if psa_crypto_sys::PSA_ALG_IS_CIPHER(alg) {
565            error!("Cipher algorithms are not supported.");
566            Err(Error::NotSupported)
567        } else if psa_crypto_sys::PSA_ALG_IS_AEAD(alg) {
568            let aead: Aead = alg.try_into()?;
569            Ok(aead.into())
570        } else if psa_crypto_sys::PSA_ALG_IS_SIGN(alg) {
571            let asym_sign: AsymmetricSignature = alg.try_into()?;
572            Ok(asym_sign.into())
573        } else if psa_crypto_sys::PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) {
574            let asym_encryption: AsymmetricEncryption = alg.try_into()?;
575            Ok(asym_encryption.into())
576        } else if psa_crypto_sys::PSA_ALG_IS_KEY_AGREEMENT(alg) {
577            let key_agreement: KeyAgreement = alg.try_into()?;
578            Ok(key_agreement.into())
579        } else if psa_crypto_sys::PSA_ALG_IS_KEY_DERIVATION(alg) {
580            let key_derivation: KeyDerivation = alg.try_into()?;
581            Ok(key_derivation.into())
582        } else {
583            error!("Can not find a valid Algorithm for {}.", alg);
584            Err(Error::NotSupported)
585        }
586    }
587}
588
589#[cfg(feature = "interface")]
590impl TryFrom<Algorithm> for psa_crypto_sys::psa_algorithm_t {
591    type Error = Error;
592    fn try_from(alg: Algorithm) -> Result<Self> {
593        match alg {
594            Algorithm::None => Ok(0),
595            Algorithm::Hash(hash) => Ok(hash.into()),
596            Algorithm::AsymmetricSignature(asym_sign) => Ok(asym_sign.into()),
597            Algorithm::AsymmetricEncryption(asym_encrypt) => Ok(asym_encrypt.into()),
598            Algorithm::Mac(mac) => Ok(mac.into()),
599            Algorithm::KeyAgreement(key_agreement) => Ok(key_agreement.into()),
600            Algorithm::KeyDerivation(key_derivation) => Ok(key_derivation.into()),
601            Algorithm::Aead(aead) => Ok(aead.into()),
602            Algorithm::Cipher(cipher) => Ok(cipher.into()),
603        }
604    }
605}
606
607#[cfg(feature = "interface")]
608impl TryFrom<psa_crypto_sys::psa_algorithm_t> for Hash {
609    type Error = Error;
610    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
611        match alg {
612            psa_crypto_sys::PSA_ALG_MD2 => Ok(Hash::Md2),
613            psa_crypto_sys::PSA_ALG_MD4 => Ok(Hash::Md4),
614            psa_crypto_sys::PSA_ALG_MD5 => Ok(Hash::Md5),
615            psa_crypto_sys::PSA_ALG_RIPEMD160 => Ok(Hash::Ripemd160),
616            psa_crypto_sys::PSA_ALG_SHA_1 => Ok(Hash::Sha1),
617            psa_crypto_sys::PSA_ALG_SHA_224 => Ok(Hash::Sha224),
618            psa_crypto_sys::PSA_ALG_SHA_256 => Ok(Hash::Sha256),
619            psa_crypto_sys::PSA_ALG_SHA_384 => Ok(Hash::Sha384),
620            psa_crypto_sys::PSA_ALG_SHA_512 => Ok(Hash::Sha512),
621            psa_crypto_sys::PSA_ALG_SHA_512_224 => Ok(Hash::Sha512_224),
622            psa_crypto_sys::PSA_ALG_SHA_512_256 => Ok(Hash::Sha512_256),
623            psa_crypto_sys::PSA_ALG_SHA3_224 => Ok(Hash::Sha3_224),
624            psa_crypto_sys::PSA_ALG_SHA3_256 => Ok(Hash::Sha3_256),
625            psa_crypto_sys::PSA_ALG_SHA3_384 => Ok(Hash::Sha3_384),
626            psa_crypto_sys::PSA_ALG_SHA3_512 => Ok(Hash::Sha3_512),
627            a => {
628                error!("Can not find a valid Hash algorithm for {}.", a);
629                Err(Error::InvalidArgument)
630            }
631        }
632    }
633}
634
635#[cfg(feature = "interface")]
636impl From<Hash> for psa_crypto_sys::psa_algorithm_t {
637    fn from(hash: Hash) -> Self {
638        match hash {
639            Hash::Md2 => psa_crypto_sys::PSA_ALG_MD2,
640            Hash::Md4 => psa_crypto_sys::PSA_ALG_MD4,
641            Hash::Md5 => psa_crypto_sys::PSA_ALG_MD5,
642            Hash::Ripemd160 => psa_crypto_sys::PSA_ALG_RIPEMD160,
643            Hash::Sha1 => psa_crypto_sys::PSA_ALG_SHA_1,
644            Hash::Sha224 => psa_crypto_sys::PSA_ALG_SHA_224,
645            Hash::Sha256 => psa_crypto_sys::PSA_ALG_SHA_256,
646            Hash::Sha384 => psa_crypto_sys::PSA_ALG_SHA_384,
647            Hash::Sha512 => psa_crypto_sys::PSA_ALG_SHA_512,
648            Hash::Sha512_224 => psa_crypto_sys::PSA_ALG_SHA_512_224,
649            Hash::Sha512_256 => psa_crypto_sys::PSA_ALG_SHA_512_256,
650            Hash::Sha3_224 => psa_crypto_sys::PSA_ALG_SHA3_224,
651            Hash::Sha3_256 => psa_crypto_sys::PSA_ALG_SHA3_256,
652            Hash::Sha3_384 => psa_crypto_sys::PSA_ALG_SHA3_384,
653            Hash::Sha3_512 => psa_crypto_sys::PSA_ALG_SHA3_512,
654        }
655    }
656}
657
658#[cfg(feature = "interface")]
659impl TryFrom<psa_crypto_sys::psa_algorithm_t> for SignHash {
660    type Error = Error;
661    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
662        if alg == psa_crypto_sys::PSA_ALG_ANY_HASH {
663            Ok(SignHash::Any)
664        } else {
665            Ok(SignHash::Specific(alg.try_into()?))
666        }
667    }
668}
669
670#[cfg(feature = "interface")]
671impl From<SignHash> for psa_crypto_sys::psa_algorithm_t {
672    fn from(sign_hash: SignHash) -> Self {
673        match sign_hash {
674            SignHash::Specific(hash) => hash.into(),
675            SignHash::Any => psa_crypto_sys::PSA_ALG_ANY_HASH,
676        }
677    }
678}
679
680#[cfg(feature = "interface")]
681impl TryFrom<psa_crypto_sys::psa_algorithm_t> for AsymmetricSignature {
682    type Error = Error;
683    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
684        if alg == psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN_RAW {
685            Ok(AsymmetricSignature::RsaPkcs1v15SignRaw)
686        } else if alg == psa_crypto_sys::PSA_ALG_ECDSA_ANY {
687            Ok(AsymmetricSignature::EcdsaAny)
688        } else if psa_crypto_sys::PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) {
689            Ok(AsymmetricSignature::RsaPkcs1v15Sign {
690                hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
691            })
692        } else if psa_crypto_sys::PSA_ALG_IS_RSA_PSS(alg) {
693            Ok(AsymmetricSignature::RsaPss {
694                hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
695            })
696        } else if psa_crypto_sys::PSA_ALG_IS_ECDSA(alg) {
697            Ok(AsymmetricSignature::Ecdsa {
698                hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
699            })
700        } else if psa_crypto_sys::PSA_ALG_IS_DETERMINISTIC_ECDSA(alg) {
701            Ok(AsymmetricSignature::DeterministicEcdsa {
702                hash_alg: psa_crypto_sys::PSA_ALG_SIGN_GET_HASH(alg).try_into()?,
703            })
704        } else {
705            error!(
706                "Can not find a valid AsymmetricSignature algorithm for {}.",
707                alg
708            );
709            Err(Error::InvalidArgument)
710        }
711    }
712}
713
714#[cfg(feature = "interface")]
715impl From<AsymmetricSignature> for psa_crypto_sys::psa_algorithm_t {
716    fn from(asym_sign: AsymmetricSignature) -> Self {
717        match asym_sign {
718            AsymmetricSignature::RsaPkcs1v15Sign { hash_alg } => {
719                psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg.into())
720            }
721            AsymmetricSignature::RsaPkcs1v15SignRaw => {
722                psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN_RAW
723            }
724            AsymmetricSignature::RsaPss { hash_alg } => {
725                psa_crypto_sys::PSA_ALG_RSA_PSS(hash_alg.into())
726            }
727            AsymmetricSignature::Ecdsa { hash_alg } => {
728                psa_crypto_sys::PSA_ALG_ECDSA(hash_alg.into())
729            }
730            AsymmetricSignature::EcdsaAny => psa_crypto_sys::PSA_ALG_ECDSA_ANY,
731            AsymmetricSignature::DeterministicEcdsa { hash_alg } => {
732                psa_crypto_sys::PSA_ALG_DETERMINISTIC_ECDSA(hash_alg.into())
733            }
734        }
735    }
736}
737
738#[cfg(feature = "interface")]
739impl TryFrom<psa_crypto_sys::psa_algorithm_t> for AsymmetricEncryption {
740    type Error = Error;
741    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
742        if alg == psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_CRYPT {
743            Ok(AsymmetricEncryption::RsaPkcs1v15Crypt)
744        } else if unsafe { psa_crypto_sys::PSA_ALG_IS_RSA_OAEP(alg) } {
745            Ok(AsymmetricEncryption::RsaOaep {
746                hash_alg: psa_crypto_sys::PSA_ALG_RSA_OAEP_GET_HASH(alg).try_into()?,
747            })
748        } else {
749            error!(
750                "Can not find a valid AsymmetricEncryption algorithm for {}.",
751                alg
752            );
753            Err(Error::InvalidArgument)
754        }
755    }
756}
757
758#[cfg(feature = "interface")]
759impl From<AsymmetricEncryption> for psa_crypto_sys::psa_algorithm_t {
760    fn from(asym_encrypt: AsymmetricEncryption) -> Self {
761        match asym_encrypt {
762            AsymmetricEncryption::RsaPkcs1v15Crypt => psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_CRYPT,
763            AsymmetricEncryption::RsaOaep { hash_alg } => unsafe {
764                psa_crypto_sys::PSA_ALG_RSA_OAEP(hash_alg.into())
765            },
766        }
767    }
768}
769
770#[cfg(feature = "interface")]
771impl From<Cipher> for psa_crypto_sys::psa_algorithm_t {
772    fn from(cipher: Cipher) -> Self {
773        match cipher {
774            Cipher::StreamCipher => psa_crypto_sys::PSA_ALG_STREAM_CIPHER,
775            Cipher::Ctr => psa_crypto_sys::PSA_ALG_CTR,
776            Cipher::Cfb => psa_crypto_sys::PSA_ALG_CFB,
777            Cipher::Ofb => psa_crypto_sys::PSA_ALG_OFB,
778            Cipher::Xts => psa_crypto_sys::PSA_ALG_XTS,
779            Cipher::EcbNoPadding => psa_crypto_sys::PSA_ALG_ECB_NO_PADDING,
780            Cipher::CbcNoPadding => psa_crypto_sys::PSA_ALG_CBC_NO_PADDING,
781            Cipher::CbcPkcs7 => psa_crypto_sys::PSA_ALG_CBC_PKCS7,
782        }
783    }
784}
785
786#[cfg(feature = "interface")]
787impl TryFrom<psa_crypto_sys::psa_algorithm_t> for Mac {
788    type Error = Error;
789    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
790        if psa_crypto_sys::PSA_ALG_IS_MAC(alg) {
791            if unsafe { psa_crypto_sys::PSA_ALG_FULL_LENGTH_MAC(alg) } == alg {
792                Ok(Mac::FullLength(alg.try_into()?))
793            } else {
794                let mac_length = unsafe { psa_crypto_sys::PSA_MAC_TRUNCATED_LENGTH(alg) };
795                let mac_alg: FullLengthMac =
796                    unsafe { psa_crypto_sys::PSA_ALG_FULL_LENGTH_MAC(alg) }.try_into()?;
797                Ok(Mac::Truncated {
798                    mac_alg,
799                    mac_length,
800                })
801            }
802        } else {
803            error!("Can not find a valid MAC algorithm for {}.", alg);
804            Err(Error::InvalidArgument)
805        }
806    }
807}
808
809#[cfg(feature = "interface")]
810impl TryFrom<psa_crypto_sys::psa_algorithm_t> for FullLengthMac {
811    type Error = Error;
812
813    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
814        if psa_crypto_sys::PSA_ALG_IS_HMAC(alg) {
815            Ok(FullLengthMac::Hmac {
816                hash_alg: psa_crypto_sys::PSA_ALG_HMAC_GET_HASH(alg).try_into()?,
817            })
818        } else if alg == psa_crypto_sys::PSA_ALG_CBC_MAC {
819            Ok(FullLengthMac::CbcMac)
820        } else if alg == psa_crypto_sys::PSA_ALG_CMAC {
821            Ok(FullLengthMac::Cmac)
822        } else {
823            error!("Can not find a valid MAC algorithm for {}.", alg);
824            Err(Error::InvalidArgument)
825        }
826    }
827}
828
829#[cfg(feature = "interface")]
830impl From<Mac> for psa_crypto_sys::psa_algorithm_t {
831    fn from(mac: Mac) -> Self {
832        match mac {
833            Mac::FullLength(full_length_mac) => full_length_mac.into(),
834            Mac::Truncated {
835                mac_alg: alg,
836                mac_length: length,
837                // The following call is NOT currently checked. If length is invalid, the return of this call is unspecified
838            } => unsafe { psa_crypto_sys::PSA_ALG_TRUNCATED_MAC(alg.into(), length) },
839        }
840    }
841}
842
843impl From<FullLengthMac> for Mac {
844    fn from(full_length_mac: FullLengthMac) -> Self {
845        Mac::FullLength(full_length_mac)
846    }
847}
848
849#[cfg(feature = "interface")]
850impl From<FullLengthMac> for psa_crypto_sys::psa_algorithm_t {
851    fn from(full_length_mac: FullLengthMac) -> Self {
852        match full_length_mac {
853            FullLengthMac::CbcMac => psa_crypto_sys::PSA_ALG_CBC_MAC,
854            FullLengthMac::Cmac => psa_crypto_sys::PSA_ALG_CMAC,
855            FullLengthMac::Hmac { hash_alg } => unsafe {
856                psa_crypto_sys::PSA_ALG_HMAC(hash_alg.into())
857            },
858        }
859    }
860}
861
862#[cfg(feature = "interface")]
863impl TryFrom<psa_crypto_sys::psa_algorithm_t> for Aead {
864    type Error = Error;
865    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
866        if let Ok(aead_with_default_length_tag) = AeadWithDefaultLengthTag::try_from(alg) {
867            Ok(Aead::AeadWithDefaultLengthTag(aead_with_default_length_tag))
868        } else {
869            // Must be shortened tag
870            let aead_alg = AeadWithDefaultLengthTag::try_from(unsafe {
871                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg)
872            })?;
873            let tag_length = psa_crypto_sys::PSA_ALG_AEAD_TAG_TRUNCATED_LENGTH(alg);
874            Ok(Aead::AeadWithShortenedTag {
875                aead_alg,
876                tag_length,
877            })
878        }
879    }
880}
881
882#[cfg(feature = "interface")]
883impl TryFrom<psa_crypto_sys::psa_algorithm_t> for AeadWithDefaultLengthTag {
884    type Error = Error;
885
886    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
887        if alg
888            == unsafe {
889                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_CCM)
890            }
891        {
892            Ok(AeadWithDefaultLengthTag::Ccm)
893        } else if alg
894            == unsafe {
895                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_GCM)
896            }
897        {
898            Ok(AeadWithDefaultLengthTag::Gcm)
899        } else if alg
900            == unsafe {
901                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(
902                    psa_crypto_sys::PSA_ALG_CHACHA20_POLY1305,
903                )
904            }
905        {
906            Ok(AeadWithDefaultLengthTag::Chacha20Poly1305)
907        } else {
908            error!("Can not find a valid Aead algorithm for {}.", alg);
909            Err(Error::InvalidArgument)
910        }
911    }
912}
913
914#[cfg(feature = "interface")]
915impl From<Aead> for psa_crypto_sys::psa_algorithm_t {
916    fn from(aead: Aead) -> Self {
917        match aead {
918            Aead::AeadWithDefaultLengthTag(aead_with_default_length_mac) => {
919                aead_with_default_length_mac.into()
920            }
921            // The following call is NOT currently checked. If length is invalid, the return of this call is unspecified
922            Aead::AeadWithShortenedTag {
923                aead_alg,
924                tag_length,
925            } => unsafe {
926                psa_crypto_sys::PSA_ALG_AEAD_WITH_SHORTENED_TAG(aead_alg.into(), tag_length)
927            },
928        }
929    }
930}
931
932#[cfg(feature = "interface")]
933impl From<AeadWithDefaultLengthTag> for psa_crypto_sys::psa_algorithm_t {
934    fn from(aead_with_default_length_tag: AeadWithDefaultLengthTag) -> Self {
935        match aead_with_default_length_tag {
936            AeadWithDefaultLengthTag::Ccm => unsafe {
937                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_CCM)
938            },
939            AeadWithDefaultLengthTag::Gcm => unsafe {
940                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(psa_crypto_sys::PSA_ALG_GCM)
941            },
942            AeadWithDefaultLengthTag::Chacha20Poly1305 => unsafe {
943                psa_crypto_sys::PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(
944                    psa_crypto_sys::PSA_ALG_CHACHA20_POLY1305,
945                )
946            },
947        }
948    }
949}
950
951impl From<AeadWithDefaultLengthTag> for Aead {
952    fn from(aead_with_default_tag_length: AeadWithDefaultLengthTag) -> Self {
953        Aead::AeadWithDefaultLengthTag(aead_with_default_tag_length)
954    }
955}
956
957#[cfg(feature = "interface")]
958impl From<KeyAgreement> for psa_crypto_sys::psa_algorithm_t {
959    fn from(key_agreement: KeyAgreement) -> Self {
960        match key_agreement {
961            KeyAgreement::Raw(raw_key_agreement) => raw_key_agreement.into(),
962            KeyAgreement::WithKeyDerivation { ka_alg, kdf_alg } => unsafe {
963                psa_crypto_sys::PSA_ALG_KEY_AGREEMENT(ka_alg.into(), kdf_alg.into())
964            },
965        }
966    }
967}
968
969#[cfg(feature = "interface")]
970impl TryFrom<psa_crypto_sys::psa_algorithm_t> for KeyAgreement {
971    type Error = Error;
972    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
973        if psa_crypto_sys::PSA_ALG_IS_KEY_AGREEMENT(alg) {
974            if psa_crypto_sys::PSA_ALG_IS_RAW_KEY_AGREEMENT(alg) {
975                Ok(KeyAgreement::Raw(alg.try_into()?))
976            } else {
977                Ok(KeyAgreement::WithKeyDerivation {
978                    ka_alg: unsafe { psa_crypto_sys::PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) }
979                        .try_into()?,
980                    kdf_alg: unsafe { psa_crypto_sys::PSA_ALG_KEY_AGREEMENT_GET_KDF(alg) }
981                        .try_into()?,
982                })
983            }
984        } else {
985            error!("Can not find a valid KeyAgreement algorithm for {}.", alg);
986            Err(Error::InvalidArgument)
987        }
988    }
989}
990
991#[cfg(feature = "interface")]
992impl TryFrom<psa_crypto_sys::psa_algorithm_t> for RawKeyAgreement {
993    type Error = Error;
994    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
995        if psa_crypto_sys::PSA_ALG_IS_FFDH(alg) {
996            Ok(RawKeyAgreement::Ffdh)
997        } else if psa_crypto_sys::PSA_ALG_IS_ECDH(alg) {
998            Ok(RawKeyAgreement::Ecdh)
999        } else {
1000            error!(
1001                "Can not find a valid RawKeyAgreement algorithm for {}.",
1002                alg
1003            );
1004            Err(Error::InvalidArgument)
1005        }
1006    }
1007}
1008
1009#[cfg(feature = "interface")]
1010impl From<RawKeyAgreement> for psa_crypto_sys::psa_algorithm_t {
1011    fn from(raw_key_agreement: RawKeyAgreement) -> Self {
1012        match raw_key_agreement {
1013            RawKeyAgreement::Ecdh => psa_crypto_sys::PSA_ALG_ECDH,
1014            RawKeyAgreement::Ffdh => psa_crypto_sys::PSA_ALG_FFDH,
1015        }
1016    }
1017}
1018
1019impl From<RawKeyAgreement> for KeyAgreement {
1020    fn from(raw_key_agreement: RawKeyAgreement) -> Self {
1021        KeyAgreement::Raw(raw_key_agreement)
1022    }
1023}
1024
1025#[cfg(feature = "interface")]
1026impl From<KeyDerivation> for psa_crypto_sys::psa_algorithm_t {
1027    fn from(key_derivation: KeyDerivation) -> Self {
1028        match key_derivation {
1029            KeyDerivation::Hkdf { hash_alg, .. } => unsafe {
1030                psa_crypto_sys::PSA_ALG_HKDF(hash_alg.into())
1031            },
1032            KeyDerivation::Tls12Prf { hash_alg, .. } => unsafe {
1033                psa_crypto_sys::PSA_ALG_TLS12_PRF(hash_alg.into())
1034            },
1035            KeyDerivation::Tls12PskToMs { hash_alg, .. } => unsafe {
1036                psa_crypto_sys::PSA_ALG_TLS12_PSK_TO_MS(hash_alg.into())
1037            },
1038        }
1039    }
1040}
1041
1042#[cfg(feature = "interface")]
1043impl TryFrom<psa_crypto_sys::psa_algorithm_t> for KeyDerivation {
1044    type Error = Error;
1045    fn try_from(alg: psa_crypto_sys::psa_algorithm_t) -> Result<Self> {
1046        if psa_crypto_sys::PSA_ALG_IS_HKDF(alg) {
1047            Ok(KeyDerivation::Hkdf {
1048                hash_alg: psa_crypto_sys::PSA_ALG_HKDF_GET_HASH(alg).try_into()?,
1049            })
1050        } else if psa_crypto_sys::PSA_ALG_IS_TLS12_PRF(alg) {
1051            Ok(KeyDerivation::Tls12Prf {
1052                hash_alg: psa_crypto_sys::PSA_ALG_TLS12_PRF_GET_HASH(alg).try_into()?,
1053            })
1054        } else if psa_crypto_sys::PSA_ALG_IS_TLS12_PSK_TO_MS(alg) {
1055            Ok(KeyDerivation::Tls12PskToMs {
1056                hash_alg: psa_crypto_sys::PSA_ALG_TLS12_PSK_TO_MS_GET_HASH(alg).try_into()?,
1057            })
1058        } else {
1059            error!("Can not find a valid KeyDerivation algorithm for {}.", alg);
1060            Err(Error::InvalidArgument)
1061        }
1062    }
1063}
1064
1065#[cfg(test)]
1066mod test {
1067    use crate::types::algorithm::{Algorithm, AsymmetricSignature, Hash, SignHash};
1068    use core::convert::{TryFrom, TryInto};
1069
1070    #[test]
1071    fn conversion() {
1072        assert_eq!(
1073            Hash::Sha256,
1074            psa_crypto_sys::PSA_ALG_SHA_256.try_into().unwrap()
1075        );
1076        assert_eq!(psa_crypto_sys::PSA_ALG_SHA_256, Hash::Sha256.into());
1077        assert_eq!(
1078            SignHash::Any,
1079            psa_crypto_sys::PSA_ALG_ANY_HASH.try_into().unwrap()
1080        );
1081        assert_eq!(
1082            SignHash::Specific(Hash::Sha256),
1083            psa_crypto_sys::PSA_ALG_SHA_256.try_into().unwrap()
1084        );
1085        assert_eq!(
1086            Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa {
1087                hash_alg: SignHash::Specific(Hash::Sha3_512),
1088            }),
1089            psa_crypto_sys::PSA_ALG_ECDSA(psa_crypto_sys::PSA_ALG_SHA3_512)
1090                .try_into()
1091                .unwrap()
1092        );
1093        assert_eq!(
1094            psa_crypto_sys::PSA_ALG_ECDSA(psa_crypto_sys::PSA_ALG_SHA3_512),
1095            Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa {
1096                hash_alg: SignHash::Specific(Hash::Sha3_512),
1097            })
1098            .try_into()
1099            .unwrap()
1100        );
1101    }
1102
1103    #[test]
1104    fn convert_fail() {
1105        let _ = AsymmetricSignature::try_from(0xDEAD_BEEF).unwrap_err();
1106        let _ = AsymmetricSignature::try_from(psa_crypto_sys::PSA_ALG_ANY_HASH).unwrap_err();
1107        let _ = Hash::try_from(psa_crypto_sys::PSA_ALG_ANY_HASH).unwrap_err();
1108        let _ = Hash::try_from(psa_crypto_sys::PSA_ALG_RSA_PKCS1V15_SIGN_RAW).unwrap_err();
1109    }
1110}