Skip to main content

mail_auth/crypto/
aws_lc.rs

1/*
2 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
3 *
4 * SPDX-License-Identifier: Apache-2.0 OR MIT
5 */
6
7//! Signing and verification keys backed by `aws-lc-rs`.
8
9use super::{
10    Algorithm, CryptoError, HashContext, HashImpl, HashOutput, Sha1, Sha256, Sha512, SigningKey,
11    VerifyingKey,
12    aws_lc_mldsa::MlDsa44,
13    composite::{
14        self, ED25519_PUBLIC_KEY_LEN, LABEL, PUBLIC_KEY_LEN, PrivateKey, PublicKey, SIGNATURE_LEN,
15        Seed, library_error, message_representative,
16    },
17    rsa_private_key_heap_size,
18};
19use crate::{
20    Error, Result,
21    dkim::Canonicalization,
22    headers::{Writable, Writer},
23};
24use aws_lc_rs::digest::{Context, SHA1_FOR_LEGACY_USE_ONLY, SHA256, SHA512};
25use aws_lc_rs::rand::SystemRandom;
26use aws_lc_rs::signature::{
27    ED25519, Ed25519KeyPair, KeyPair, RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
28    RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, RSA_PKCS1_SHA256, RsaKeyPair,
29    UnparsedPublicKey,
30};
31use rustls_pki_types::{PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, pem::PemObject};
32use std::marker::PhantomData;
33
34const ED25519_PRIVATE_KEY_HEAP_SIZE: usize = 112;
35const MLDSA44_PRIVATE_KEY_HEAP_SIZE: usize = 4096;
36const MLDSA44_PUBLIC_KEY_HEAP_SIZE: usize = 1600;
37
38/// An RSA private key for `rsa-sha256` signing (RFC 6376 Section 3.3.2).
39///
40/// `T` selects the hash function; only `RsaKey<Sha256>` implements
41/// [`SigningKey`]. Load a key with [`from_key_der`](Self::from_key_der).
42#[derive(Debug)]
43pub struct RsaKey<T> {
44    inner: RsaKeyPair,
45    rng: SystemRandom,
46    padding: PhantomData<T>,
47}
48
49impl<T: HashImpl> RsaKey<T> {
50    /// Loads an RSA private key from a PKCS #8 PEM string.
51    ///
52    /// # Errors
53    ///
54    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
55    /// cannot be decoded.
56    #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
57    pub fn from_pkcs8_pem(pkcs8_pem: &str) -> Result<Self> {
58        Self::from_key_der(PrivateKeyDer::Pkcs8(
59            PrivatePkcs8KeyDer::from_pem_slice(pkcs8_pem.as_bytes())
60                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
61        ))
62    }
63
64    /// Loads an RSA private key from PKCS #8 DER bytes.
65    ///
66    /// # Errors
67    ///
68    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
69    /// cannot be decoded.
70    #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
71    pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
72        Self::from_key_der(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(pkcs8_der)))
73    }
74
75    /// Loads an RSA private key from a PKCS #1 PEM string
76    /// (`BEGIN RSA PRIVATE KEY`).
77    ///
78    /// # Errors
79    ///
80    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
81    /// cannot be decoded.
82    #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
83    pub fn from_rsa_pem(rsa_pem: &str) -> Result<Self> {
84        Self::from_key_der(PrivateKeyDer::Pkcs1(
85            PrivatePkcs1KeyDer::from_pem_slice(rsa_pem.as_bytes())
86                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
87        ))
88    }
89
90    /// Loads an RSA private key from PKCS #1 DER bytes.
91    ///
92    /// # Errors
93    ///
94    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
95    /// cannot be decoded.
96    #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
97    pub fn from_der(der: &[u8]) -> Result<Self> {
98        Self::from_key_der(PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(der)))
99    }
100
101    /// Loads an RSA private key from DER, in PKCS #1 (`RSAPrivateKey`) or
102    /// PKCS #8 (`PrivateKeyInfo`) form. Parse PEM input first with
103    /// [`PrivateKeyDer::from_pem_slice`](rustls_pki_types::pem::PemObject::from_pem_slice).
104    ///
105    /// # Errors
106    ///
107    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key is
108    /// in another format (such as SEC1) or cannot be decoded.
109    pub fn from_key_der(key_der: PrivateKeyDer<'_>) -> Result<Self> {
110        let inner = match key_der {
111            PrivateKeyDer::Pkcs1(der) => RsaKeyPair::from_der(der.secret_pkcs1_der())
112                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
113            PrivateKeyDer::Pkcs8(der) => RsaKeyPair::from_pkcs8(der.secret_pkcs8_der())
114                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
115            _ => {
116                return Err(Error::Crypto(CryptoError::Library(
117                    "Unsupported RSA key format".to_string(),
118                )));
119            }
120        };
121
122        Ok(Self {
123            inner,
124            rng: SystemRandom::new(),
125            padding: PhantomData,
126        })
127    }
128
129    /// Returns the public key of the RSA key pair, encoded as a DER PKCS #1
130    /// `RSAPublicKey`.
131    pub fn public_key(&self) -> Vec<u8> {
132        self.inner.public_key().as_ref().to_vec()
133    }
134}
135
136impl SigningKey for RsaKey<Sha256> {
137    type Hasher = Sha256;
138
139    fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
140        let mut data = Vec::with_capacity(256);
141        input.write(&mut data);
142
143        let mut signature = vec![0; self.inner.public_key().modulus_len()];
144        self.inner
145            .sign(&RSA_PKCS1_SHA256, &self.rng, &data, &mut signature)
146            .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?;
147        Ok(signature)
148    }
149
150    fn algorithm(&self) -> Algorithm {
151        Algorithm::RsaSha256
152    }
153
154    fn heap_size(&self) -> usize {
155        rsa_private_key_heap_size(self.inner.public_key().modulus_len())
156    }
157}
158
159/// An Ed25519 private key for `ed25519-sha256` signing (RFC 8463).
160///
161/// The signature is computed over the SHA-256 hash of the signed data, as
162/// RFC 8463 Section 3 requires.
163pub struct Ed25519Key {
164    inner: Ed25519KeyPair,
165}
166
167impl Ed25519Key {
168    /// Generates a new random Ed25519 key pair and returns it as PKCS #8 DER
169    /// bytes, ready for [`from_pkcs8_der`](Self::from_pkcs8_der).
170    ///
171    /// # Errors
172    ///
173    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if key
174    /// generation or encoding fails.
175    pub fn generate_pkcs8() -> Result<Vec<u8>> {
176        Ok(Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())
177            .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?
178            .as_ref()
179            .to_vec())
180    }
181
182    /// Loads an Ed25519 key pair from PKCS #8 v2 DER bytes (RFC 5958), checking
183    /// that the embedded public key matches the private key. PKCS #8 v1
184    /// documents are rejected by `ring`; load them with
185    /// [`from_pkcs8_maybe_unchecked_der`](Self::from_pkcs8_maybe_unchecked_der).
186    ///
187    /// # Errors
188    ///
189    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
190    /// cannot be decoded.
191    pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
192        Ok(Self {
193            inner: Ed25519KeyPair::from_pkcs8(pkcs8_der)
194                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
195        })
196    }
197
198    /// Loads an Ed25519 key pair from PKCS #8 v1 or v2 DER bytes. A v1
199    /// document (as produced by `openssl genpkey -algorithm ED25519`) carries
200    /// no public key, so no consistency check is possible; v2 documents are
201    /// checked as in [`from_pkcs8_der`](Self::from_pkcs8_der).
202    ///
203    /// # Errors
204    ///
205    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
206    /// cannot be decoded.
207    pub fn from_pkcs8_maybe_unchecked_der(pkcs8_der: &[u8]) -> Result<Self> {
208        Ok(Self {
209            inner: Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8_der)
210                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
211        })
212    }
213
214    /// Builds an Ed25519 key pair from its 32-byte seed (private key) and
215    /// 32-byte public key.
216    ///
217    /// # Errors
218    ///
219    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if either
220    /// value has the wrong length or the public key does not match the seed.
221    pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self> {
222        Ok(Self {
223            inner: Ed25519KeyPair::from_seed_and_public_key(seed, public_key)
224                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
225        })
226    }
227
228    /// Returns the 32-byte raw Ed25519 public key, as published in the `p=`
229    /// tag of a DKIM key record.
230    pub fn public_key(&self) -> Vec<u8> {
231        self.inner.public_key().as_ref().to_vec()
232    }
233}
234
235impl SigningKey for Ed25519Key {
236    type Hasher = Sha256;
237
238    fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
239        let mut data = Sha256::hasher();
240        input.write(&mut data);
241        Ok(self.inner.sign(data.complete().as_ref()).as_ref().to_vec())
242    }
243
244    fn algorithm(&self) -> Algorithm {
245        Algorithm::Ed25519Sha256
246    }
247
248    fn heap_size(&self) -> usize {
249        ED25519_PRIVATE_KEY_HEAP_SIZE
250    }
251}
252
253pub(crate) struct RsaPublicKey {
254    key: Vec<u8>,
255}
256
257impl RsaPublicKey {
258    pub(crate) fn verifying_key_from_bytes(
259        bytes: &[u8],
260    ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
261        Ok(Box::new(Self {
262            key: try_strip_rsa_prefix(bytes).unwrap_or(bytes).to_vec(),
263        }))
264    }
265}
266
267/// Computes the RSA modulus size in bits from a DER-encoded RSAPublicKey
268fn rsa_modulus_bits(key: &[u8]) -> Option<usize> {
269    if *key.first()? != DER_SEQUENCE_TAG {
270        return None;
271    }
272    let (_, rest) = decode_multi_byte_len(&key[1..])?;
273    if *rest.first()? != DER_INTEGER_TAG {
274        return None;
275    }
276    let (len, after_len) = decode_multi_byte_len(&rest[1..])?;
277    after_len
278        .get(..len)?
279        .iter()
280        .position(|&b| b != 0)
281        .map(|leading_zeros| (len - leading_zeros) * 8)
282}
283
284/// Try to strip an ASN.1 DER-encoded RSA public key prefix
285///
286/// Returns the original slice if the prefix is not found.
287fn try_strip_rsa_prefix(bytes: &[u8]) -> Option<&[u8]> {
288    if *bytes.first()? != DER_SEQUENCE_TAG {
289        return None;
290    }
291
292    let (_, bytes) = decode_multi_byte_len(&bytes[1..])?;
293    if *bytes.first()? != DER_SEQUENCE_TAG {
294        return None;
295    }
296
297    let (byte_len, bytes) = decode_multi_byte_len(&bytes[1..])?;
298    if *bytes.first()? != DER_OBJECT_ID_TAG || byte_len != 13 {
299        return None;
300    }
301
302    let bytes = bytes.get(13..)?;
303    if *bytes.first()? != DER_BIT_STRING_TAG {
304        return None;
305    }
306
307    decode_multi_byte_len(&bytes[1..]).and_then(|(_, bytes)| bytes.get(1..))
308}
309
310fn decode_multi_byte_len(bytes: &[u8]) -> Option<(usize, &[u8])> {
311    if bytes.first()? & 0x80 == 0 {
312        return Some((bytes[0] as usize, &bytes[1..]));
313    }
314
315    let len_len = (bytes[0] & 0x7f) as usize;
316    if bytes.len() < len_len + 1 {
317        return None;
318    }
319
320    let mut len = 0;
321    for i in 0..len_len {
322        len = (len << 8) | bytes[1 + i] as usize;
323    }
324
325    Some((len, &bytes[len_len + 1..]))
326}
327
328const DER_OBJECT_ID_TAG: u8 = 0x06;
329const DER_BIT_STRING_TAG: u8 = 0x03;
330const DER_SEQUENCE_TAG: u8 = 0x30;
331const DER_INTEGER_TAG: u8 = 0x02;
332
333impl VerifyingKey for RsaPublicKey {
334    fn verify<'a>(
335        &self,
336        headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
337        signature: &[u8],
338        canonicalization: Canonicalization,
339        algorithm: Algorithm,
340    ) -> Result<()> {
341        let mut data = Vec::with_capacity(256);
342        canonicalization.canonicalize_headers(headers, &mut data);
343
344        match algorithm {
345            Algorithm::RsaSha256 => UnparsedPublicKey::new(
346                &RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
347                self.key.as_slice(),
348            )
349            .verify(&data, signature)
350            .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
351            Algorithm::RsaSha1 => UnparsedPublicKey::new(
352                &RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
353                self.key.as_slice(),
354            )
355            .verify(&data, signature)
356            .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
357            Algorithm::Ed25519Sha256 | Algorithm::MlDsa44Ed25519Sha512 => {
358                Err(Error::Crypto(CryptoError::IncompatibleAlgorithms))
359            }
360        }
361    }
362
363    fn verify_bytes(&self, input: &[u8], signature: &[u8], algorithm: Algorithm) -> Result<()> {
364        match algorithm {
365            Algorithm::RsaSha256 => UnparsedPublicKey::new(
366                &RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
367                self.key.as_slice(),
368            )
369            .verify(input, signature)
370            .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
371            Algorithm::RsaSha1 => UnparsedPublicKey::new(
372                &RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
373                self.key.as_slice(),
374            )
375            .verify(input, signature)
376            .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
377            Algorithm::Ed25519Sha256 | Algorithm::MlDsa44Ed25519Sha512 => {
378                Err(Error::Crypto(CryptoError::IncompatibleAlgorithms))
379            }
380        }
381    }
382
383    fn public_key_bits(&self) -> usize {
384        rsa_modulus_bits(&self.key).unwrap_or_default()
385    }
386
387    fn heap_size(&self) -> usize {
388        self.key.capacity()
389    }
390}
391
392pub(crate) struct Ed25519PublicKey {
393    inner: UnparsedPublicKey<Vec<u8>>,
394}
395
396impl Ed25519PublicKey {
397    pub(crate) fn verifying_key_from_bytes(
398        bytes: &[u8],
399    ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
400        Ok(Box::new(Self {
401            inner: UnparsedPublicKey::new(&ED25519, bytes.to_vec()),
402        }))
403    }
404}
405
406impl VerifyingKey for Ed25519PublicKey {
407    fn verify<'a>(
408        &self,
409        headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
410        signature: &[u8],
411        canonicalization: Canonicalization,
412        algorithm: Algorithm,
413    ) -> Result<()> {
414        if !matches!(algorithm, Algorithm::Ed25519Sha256) {
415            return Err(Error::Crypto(CryptoError::IncompatibleAlgorithms));
416        }
417
418        let mut hasher = Sha256::hasher();
419        canonicalization.canonicalize_headers(headers, &mut hasher);
420        self.inner
421            .verify(hasher.complete().as_ref(), signature)
422            .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))
423    }
424
425    fn verify_bytes(&self, input: &[u8], signature: &[u8], algorithm: Algorithm) -> Result<()> {
426        if !matches!(algorithm, Algorithm::Ed25519Sha256) {
427            return Err(Error::Crypto(CryptoError::IncompatibleAlgorithms));
428        }
429
430        let mut hasher = Sha256::hasher();
431        hasher.write(input);
432        self.inner
433            .verify(hasher.complete().as_ref(), signature)
434            .map_err(|_| Error::Crypto(CryptoError::FailedVerification))
435    }
436
437    fn heap_size(&self) -> usize {
438        self.inner.as_ref().len()
439    }
440}
441
442/// An ML-DSA-44/Ed25519 composite private key for `mldsa44-ed25519-sha512`
443/// signing (DKIM2 only), the `id-MLDSA44-Ed25519-SHA512` algorithm of
444/// draft-ietf-lamps-pq-composite-sigs.
445///
446/// The private key is the 32-byte ML-DSA-44 seed followed by the 32-byte
447/// Ed25519 seed. ML-DSA-44 signatures are hedged (randomized), as FIPS 204
448/// recommends, so signing the same input twice gives different signatures.
449pub struct MlDsa44Ed25519Key {
450    mldsa: MlDsa44,
451    ed25519: Ed25519KeyPair,
452}
453
454impl MlDsa44Ed25519Key {
455    /// Generates a new random key and returns it as PKCS #8 DER bytes (the
456    /// `id-MLDSA44-Ed25519-SHA512` private key encoding), ready for
457    /// [`from_pkcs8_der`](Self::from_pkcs8_der).
458    ///
459    /// # Errors
460    ///
461    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the system
462    /// random number generator fails.
463    pub fn generate_pkcs8() -> Result<Vec<u8>> {
464        let mut mldsa = Seed::default();
465        let mut ed25519 = Seed::default();
466        aws_lc_rs::rand::fill(&mut mldsa)
467            .and_then(|()| aws_lc_rs::rand::fill(&mut ed25519))
468            .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?;
469        Ok(composite::pkcs8_der(&mldsa, &ed25519))
470    }
471
472    /// Loads a key from PKCS #8 DER bytes holding an
473    /// `id-MLDSA44-Ed25519-SHA512` private key.
474    ///
475    /// # Errors
476    ///
477    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key
478    /// cannot be decoded.
479    pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
480        Self::from_private_key(PrivateKey::from_pkcs8_der(pkcs8_der)?)
481    }
482
483    /// Loads a key from its 64-byte raw form: the ML-DSA-44 seed followed by
484    /// the Ed25519 seed.
485    ///
486    /// # Errors
487    ///
488    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the key has
489    /// the wrong length or cannot be expanded.
490    pub fn from_raw_private_key(raw: &[u8]) -> Result<Self> {
491        Self::from_private_key(PrivateKey::from_raw(raw)?)
492    }
493
494    fn from_private_key(key: PrivateKey<'_>) -> Result<Self> {
495        Ok(Self {
496            mldsa: MlDsa44::from_seed(key.mldsa)
497                .ok_or_else(|| library_error("Invalid ML-DSA-44 seed"))?,
498            ed25519: Ed25519KeyPair::from_seed_unchecked(key.ed25519)
499                .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
500        })
501    }
502
503    /// Returns the 1344-byte composite public key (the ML-DSA-44 public key
504    /// followed by the Ed25519 public key), as published in the `p=` tag of
505    /// a `k=mldsa44-ed25519-sha512` key record.
506    ///
507    /// # Errors
508    ///
509    /// Returns [`Error::Crypto`] with [`CryptoError::Library`] if the backend
510    /// cannot export the ML-DSA-44 public key.
511    pub fn public_key(&self) -> Result<Vec<u8>> {
512        let mldsa = self
513            .mldsa
514            .public_key()
515            .ok_or_else(|| library_error("Cannot export the ML-DSA-44 public key"))?;
516        let mut key = Vec::with_capacity(PUBLIC_KEY_LEN);
517        key.extend_from_slice(&mldsa);
518        key.extend_from_slice(self.ed25519.public_key().as_ref());
519        Ok(key)
520    }
521}
522
523impl SigningKey for MlDsa44Ed25519Key {
524    type Hasher = Sha512;
525
526    fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
527        let representative = message_representative(input);
528        let mldsa = self
529            .mldsa
530            .sign(&representative, LABEL)
531            .ok_or_else(|| library_error("ML-DSA-44 signing failed"))?;
532        let mut signature = Vec::with_capacity(SIGNATURE_LEN);
533        signature.extend_from_slice(&mldsa);
534        signature.extend_from_slice(self.ed25519.sign(&representative).as_ref());
535        Ok(signature)
536    }
537
538    fn algorithm(&self) -> Algorithm {
539        Algorithm::MlDsa44Ed25519Sha512
540    }
541
542    fn heap_size(&self) -> usize {
543        MLDSA44_PRIVATE_KEY_HEAP_SIZE + ED25519_PRIVATE_KEY_HEAP_SIZE
544    }
545}
546
547pub(crate) struct MlDsa44Ed25519PublicKey {
548    mldsa: MlDsa44,
549    ed25519: UnparsedPublicKey<[u8; ED25519_PUBLIC_KEY_LEN]>,
550}
551
552impl MlDsa44Ed25519PublicKey {
553    pub(crate) fn verifying_key_from_bytes(
554        bytes: &[u8],
555    ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
556        let key = PublicKey::from_bytes(bytes)?;
557        Ok(Box::new(Self {
558            mldsa: MlDsa44::from_public_key(key.mldsa)
559                .ok_or_else(|| library_error("Invalid ML-DSA-44 public key"))?,
560            ed25519: UnparsedPublicKey::new(&ED25519, *key.ed25519),
561        }))
562    }
563}
564
565impl VerifyingKey for MlDsa44Ed25519PublicKey {
566    fn verify<'a>(
567        &self,
568        _: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
569        _: &[u8],
570        _: Canonicalization,
571        _: Algorithm,
572    ) -> Result<()> {
573        Err(Error::Crypto(CryptoError::IncompatibleAlgorithms))
574    }
575
576    fn verify_bytes(&self, input: &[u8], signature: &[u8], algorithm: Algorithm) -> Result<()> {
577        if !matches!(algorithm, Algorithm::MlDsa44Ed25519Sha512) {
578            return Err(Error::Crypto(CryptoError::IncompatibleAlgorithms));
579        }
580        let signature = composite::Signature::from_bytes(signature)
581            .ok_or(Error::Crypto(CryptoError::FailedVerification))?;
582        let representative = message_representative(input);
583        if self.mldsa.verify(&representative, LABEL, signature.mldsa)
584            && self
585                .ed25519
586                .verify(&representative, signature.ed25519)
587                .is_ok()
588        {
589            Ok(())
590        } else {
591            Err(Error::Crypto(CryptoError::FailedVerification))
592        }
593    }
594
595    fn heap_size(&self) -> usize {
596        MLDSA44_PUBLIC_KEY_HEAP_SIZE
597    }
598}
599
600impl HashImpl for Sha1 {
601    type Context = Context;
602
603    fn hasher() -> Self::Context {
604        Context::new(&SHA1_FOR_LEGACY_USE_ONLY)
605    }
606}
607
608impl HashImpl for Sha256 {
609    type Context = Context;
610
611    fn hasher() -> Self::Context {
612        Context::new(&SHA256)
613    }
614}
615
616impl HashImpl for Sha512 {
617    type Context = Context;
618
619    fn hasher() -> Self::Context {
620        Context::new(&SHA512)
621    }
622}
623
624impl HashContext for Context {
625    fn complete(self) -> HashOutput {
626        HashOutput::Digest(self.finish())
627    }
628}
629
630impl Writer for Context {
631    fn write(&mut self, data: &[u8]) {
632        self.update(data);
633    }
634}
635
636#[cfg(test)]
637mod tests {
638    use super::*;
639
640    #[test]
641    fn from_key_der_pkcs1() {
642        let key_der = PrivateKeyDer::from_pem_slice(PKCS1_PEM.as_bytes()).unwrap();
643        assert!(matches!(key_der, PrivateKeyDer::Pkcs1(_)));
644        RsaKey::<Sha256>::from_key_der(key_der).unwrap();
645    }
646
647    #[test]
648    fn from_key_der_pkcs8() {
649        let key_der = PrivateKeyDer::from_pem_slice(PKCS8_PEM.as_bytes()).unwrap();
650        assert!(matches!(key_der, PrivateKeyDer::Pkcs8(_)));
651        RsaKey::<Sha256>::from_key_der(key_der).unwrap();
652    }
653
654    const PKCS1_PEM: &str = r#"-----BEGIN RSA PRIVATE KEY-----
655MIIEoAIBAAKCAQEAplSshLNG7gYj7LckWBQ5Gg1mrFGj2soo3VuMKSbvfR6tMrnj
656khKUSl3TWQyKdkuOOf4EzAyxhJdq/hWGvMdwfwH2q4UzjjcaRHDP54oBH6WHxyAn
657UUkJTFfJo2i8jFE/um09igLr5sEaKMiHgjQIdUScuQRGqKhqS9e4tPpTnfP4ayvM
658zVvD1ptUnaV4O9+GkpEwx/vLVXItMO2KNXXKADYBuWcY9g+Dlpp637radmLJjnvj
659bCJipWjuVzUEQvIvf3x1dZ4b899Bycp4uScmdz5brfxkhLaA9vchnmr+F7aAuwwK
660N5X2Ep6n5d1M0XjA02Z9Zi2W4NkZiNBBmb/f6QIDAQABAoIBAAPzPANNGv4L98jx
661+C3o/F/YbyE1sXmV9lP8I1nr1+FbETvEleQSHGL1aPpIVbZ6/gugXdP3E4qFqmUS
662ik1hQtRFWJVuDPwk5ghiPHxwIYLd+cRFHiHsT96isWzNJTiDinWpN/5XKkE5QfTe
663KaJc4tGJebEG1LhsgtUTxbTImCPxYvKUItDlApOusVvhARjqCnXunNEu5iDiADHH
664Wsv3eSPdWkdF5Jjgt/bI4I9XmagX3e1z6ZQiGvdBwCc8ccwkU6yTswXgWCPqyw/t
665lbTFqE19lEoHGTYYElKaHUo9hCmI3HZS69ShYKG7dMT9dVLhzRlNx7AzZcYWh8Mx
666Ptc8OY0CgYEA1LJe5EpfJ/XvzbiVtNiq07CGhlQj62DAH+XpyqtWHHrUNgMbnBZS
66729had9h2NyfIFDIZAKPGWRuSB6PSyDR6w5Sugh5nRoXshzaFr1pAHmo18s+QELjj
668XyccwivxRXurwmdDL5Bx0YCKII4LJyE3CBlJzq0/wOxvi+iKDRG+TIUCgYEAyDG8
669DXk+E6f9Vd4phaN3sLVDd228U/NNuEr+K74AFHwomgEv//KdK2i/EjFq0zGf31jE
670QMoVbnTDmmzVPfKRDlD3tk5XIz2TDzgGxOYBIWJLUiOlkXxckbLVJBR3NxKn561n
671id7vMR8ik+hAhEp9yZishZr+QrS/4AyHR3ahBRUCgYBYgoGKboh6kJVh/lYOE7vC
672q8rPS2RHJtPMclh/xhznbRWyBEkRAxkn8zhydtl6ykswXEibQ4veuOJj24BzX6NW
673kCCudQh1CHYNLlsjRWM5ROl+SXGiA85aYmRNSQv15ijrlR0YRfuXOu4/7dwmRGQq
674MpvMLbxCBCHHDtWj6qZOIQKBgF+3F7hBbaKsQP2bGLMicwlzwOwK9W4V9+TTRi7X
675yuYAbtEjHDX9Y5Prot8p7W9IXK3GnR51AEYtYZAl1NancR8tKyJo1lStDfDK0sG1
676TnkNrAF7tZ+XnBK1NB7qAg28x7aHO+e5RRdxUXDyLFaT3wxSCLpgXoy6KrsOgmdy
677mo35An9pYQ3Ik9ghh3PJsQ0r/TywuKIzmSvLJZfI/cuBOFkPDoWCleQGdzyQcxuc
678PSCtw8eXUj/Oc09qo5dRWXQkt5uW8sJB0k5fNnfCDqNReUXavDNXOHq31J5USy5R
6798ts1bmtZtK0oRci6A8PcgWChUvSfFUT5IrQM/x4rxabn8qIK
680-----END RSA PRIVATE KEY-----
681"#;
682
683    const PKCS8_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
684MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXxo5+n7aZ0psn
685dNjs53za9Af657AuG3sVnvWEBf24OvwwWClJ5vN+cWA7V2yIuuVvd40RxX1N4HLX
686QewaUBVw+XlHanskcYA8WTVuMTI6XNY6hIAtU1ETSWAPke5sH6DyrAzxIoC2R+IH
687ejqwjtdWdQ0MNVudqY3BO6mAH+zYblRzytMmcols+aqYNgZeAYuEie+EiJiTT65v
688y0mG24k0ALF5XLPahxhoUK/xuhjjG/Y/InD8s6C4BksO29bStnyqhMToSGMtUyOT
689PTyh1XgrUB4dlfEnpfX9F/wU8a7ijrD38Qtg935c08Qg9YcwVXzpFHWRw/ZF/auq
690lcazbMaHAgMBAAECggEAOKmhncrfLsHJkLD0jjGz7eOLfO3+q/z3c5QMsSDJoemL
691dD6SiR+m7ZtkQ/EPRVCfE4h3eSU9ZIf+YFylXbuOBd7dZE2oDMfpfu+GQmuU3xKm
692BzPoXP62GbR5D12pGKetokxgEaqX1kZGKuSEKP05uzB9vqj8aAiwev/p4QWBMsw6
6932stumeWMuZortwL9PZpXgzpJPHXDnFdsn3OIINBMFYFdqda8RhL3rWWsbV5nL1oR
694Q2/SMPLc1dQ8ZQKdPmbVhdfnPitVKVEkn8xIiFPWNS3SfYIi+wQj0lWdJbvUUJ1i
6957BIXvnXeeVLyYhekTpE5ZnGeGI4A5lix4PN+GIao8QKBgQDtuPW8BaXWfPHb93Kl
696mWBQNHz0I71p8GL9/+xRpA9SMuUtYS0jJ1whNgcwoSI4cOKo1UsIMDPAPpTU47Ul
6970D+vXr/GyiONL6+IsXAf5xhaQnUWRWKs4G9obadyGkT8aH6y8W+ddKD1JWQKUf4t
698Bmpeim+Ck0I8POhDbNNfThTLwwKBgQDoXZ70Pb6HViZAbzf+rEznNycgG8IqtTSc
699V7YoSMZe17u0AQjE9XZizBrhpz47N6/JvyYTBIh6VPQe880FTnHdUjvbqn8bmLE7
700QEYwvgF5hmHVXlWXUsyKbfMH5Dp8Uy74FV2VTd1hJ7UMSke7LQT41Hgyaz32x7Lm
701r0P63fgh7QKBgQDMrnCGz6YWo8XrS4efJgxTgp4D57HzQVM6t9xV/xhiAghppj4j
702AoTE46wVJug8CJZgICZWiopEgJ3NH7KdOE1dRguBshIiQmi1HXIZRfUl4grGfj+T
7038jp6g8+k4xF68s4EbPVZcU4VRXh5mldrlRaJCFEy8HAbRaYGR/FHIget2QKBgGd/
704o9h4VBAmAD29DDzkdBCc0VGM66xoL/nfW6SP3cPK5bFksIpCJywUa3jNLHvl7ue2
705u3fHEh8jDeVnhI9zhGYnRcAvLhSVq4OPunPlffSqNZN7RDZ1y+Nw28pNDvvndUlN
706AvUIzK2EqTDDOTYW9Fr9EFisydnM01PLB0WLbwV1AoGAGmaWcbNfPyPnJU1nIHGG
707fPlEpGn+3Oxr1ja02FPwexk/bg6CRVIqP2x7RtR1cH9fOqiDOoIqyfKswuZkwVj3
708EMeos/WHHrw+UzXem+IswmwG9rnUBMlMRCkJ9GhXk98bqoWeJpMhlj1L+oBQ3Spj
709j8T1spkdY4jj3CvmzQ0ha0U=
710-----END PRIVATE KEY-----
711"#;
712}