libcrux/
signature.rs

1//! # Signatures
2//!
3//! * EcDSA P256 with Sha256, Sha384, and Sha512
4//! * EdDSA 25519
5//! * RSA PSS
6
7use rand::{CryptoRng, Rng, RngCore};
8
9use crate::{
10    ecdh,
11    hacl::{self, ed25519, p256},
12};
13
14use self::rsa_pss::RsaPssSignature;
15
16/// Signature Errors
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Error {
19    SigningError,
20    InvalidSignature,
21    KeyGenError,
22    InvalidKey,
23    InputTooLarge,
24}
25
26/// The digest algorithm used for the signature scheme (when required).
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum DigestAlgorithm {
29    Sha256,
30    Sha384,
31    Sha512,
32}
33
34/// The Signature Algorithm
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Algorithm {
37    EcDsaP256(DigestAlgorithm),
38    Ed25519,
39    RsaPss(DigestAlgorithm),
40}
41
42/// The signature
43#[derive(Debug)]
44pub enum Signature {
45    EcDsaP256(EcDsaP256Signature),
46    Ed25519(Ed25519Signature),
47    RsaPss(RsaPssSignature),
48}
49
50impl Signature {
51    /// Convert the signature into a raw byte vector.
52    ///
53    /// * NIST P Curve signatures are returned as `r || s`.
54    /// * RSA PSS signatures are returned as the raw bytes.
55    pub fn into_vec(self) -> Vec<u8> {
56        match self {
57            Signature::EcDsaP256(s) => {
58                let mut out = s.r.to_vec();
59                out.extend_from_slice(&s.s);
60                out
61            }
62            Signature::Ed25519(s) => s.signature.to_vec(),
63            Signature::RsaPss(s) => s.value,
64        }
65    }
66}
67
68/// A [`Algorithm::EcDsaP256`] Signature
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub struct EcDsaP256Signature {
71    r: [u8; 32],
72    s: [u8; 32],
73    alg: Algorithm,
74}
75
76/// A [`Algorithm::Ed25519`] Signature
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct Ed25519Signature {
79    signature: [u8; 64],
80}
81
82pub mod rsa_pss {
83    use libcrux_hacl::{
84        hacl_free, Hacl_RSAPSS_new_rsapss_load_pkey, Hacl_RSAPSS_new_rsapss_load_skey,
85        Hacl_RSAPSS_rsapss_sign, Hacl_RSAPSS_rsapss_verify,
86    };
87
88    use super::{DigestAlgorithm, Error};
89
90    /// A [`Algorithm::RsaPss`] Signature
91    #[derive(Debug, Clone, PartialEq, Eq)]
92    pub struct RsaPssSignature {
93        pub(super) value: Vec<u8>,
94    }
95
96    impl RsaPssSignature {
97        /// Get the signature as the raw byte slice.
98        pub fn as_bytes(&self) -> &[u8] {
99            &self.value
100        }
101    }
102
103    impl From<&[u8]> for RsaPssSignature {
104        fn from(value: &[u8]) -> Self {
105            Self {
106                value: value.to_vec(),
107            }
108        }
109    }
110
111    impl<const L: usize> From<[u8; L]> for RsaPssSignature {
112        fn from(value: [u8; L]) -> Self {
113            Self {
114                value: value.to_vec(),
115            }
116        }
117    }
118
119    impl From<Vec<u8>> for RsaPssSignature {
120        fn from(value: Vec<u8>) -> Self {
121            Self { value }
122        }
123    }
124
125    /// A [`Algorithm::RsaPss`] public key.
126    #[derive(Debug, Clone, PartialEq, Eq)]
127    pub struct RsaPssPublicKey {
128        n: Vec<u8>,
129    }
130
131    fn rsa_pss_digest(hash_algorithm: DigestAlgorithm) -> u8 {
132        match hash_algorithm {
133            DigestAlgorithm::Sha256 => libcrux_hacl::Spec_Hash_Definitions_SHA2_256 as u8,
134            DigestAlgorithm::Sha384 => libcrux_hacl::Spec_Hash_Definitions_SHA2_384 as u8,
135            DigestAlgorithm::Sha512 => libcrux_hacl::Spec_Hash_Definitions_SHA2_512 as u8,
136        }
137    }
138
139    /// The key size is the bit/byte-size of the modulus N.
140    /// Note that the values are bytes but the names are in bits.
141    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
142    #[repr(usize)]
143    pub enum RsaPssKeySize {
144        /// N = 2048 bits | 256 bytes
145        N2048 = 256,
146
147        /// N = 3072 bits | 384 bytes
148        N3072 = 384,
149
150        /// N = 4096 bits | 512 bytes
151        N4096 = 512,
152
153        /// N = 6144 bits | 768 bytes
154        N6144 = 768,
155
156        /// N = 8192 bits | 1024 bytes
157        N8192 = 1024,
158    }
159
160    // Size of e.
161    const E_BITS: u32 = 24;
162
163    // We only support this e.
164    const E: [u8; 3] = [0x01, 0x00, 0x01];
165
166    impl RsaPssPublicKey {
167        pub fn new(key_size: RsaPssKeySize, n: &[u8]) -> Result<Self, Error> {
168            if n.len() != key_size as usize {
169                return Err(Error::InvalidKey);
170            }
171            Ok(Self { n: n.into() })
172        }
173
174        /// Verify the `signature` on the `msg` with the `public_key` using the
175        /// `hash_algorithm` and `salt_len`.
176        ///
177        /// Returns an error if any of the inputs are invalid or the signature is
178        /// invalid.
179        #[must_use = "The result of the signature verification must be used."]
180        pub fn verify(
181            &self,
182            hash_algorithm: DigestAlgorithm,
183            signature: &RsaPssSignature,
184            msg: &[u8],
185            salt_len: usize,
186        ) -> Result<(), Error> {
187            let key_size_bits = (self.n.len() as u32) * 8;
188            unsafe {
189                let pkey = Hacl_RSAPSS_new_rsapss_load_pkey(
190                    key_size_bits,
191                    E_BITS,
192                    self.n.as_ptr() as _,
193                    E.as_ptr() as _,
194                );
195                if Hacl_RSAPSS_rsapss_verify(
196                    rsa_pss_digest(hash_algorithm),
197                    key_size_bits,
198                    E_BITS,
199                    pkey,
200                    salt_len as u32,
201                    signature.value.len() as u32,
202                    signature.value.as_ptr() as _,
203                    msg.len() as u32,
204                    msg.as_ptr() as _,
205                ) {
206                    return Ok(());
207                }
208            }
209            Err(Error::InvalidSignature)
210        }
211    }
212
213    /// An RSA-PSS private key.
214    /// The private key holds a [`RsaPssPublicKey`] with the public modulus.
215    /// A [`Algorithm::RsaPss`] private key.
216    pub struct RsaPssPrivateKey<'a> {
217        pk: &'a RsaPssPublicKey,
218        d: Vec<u8>,
219    }
220
221    impl<'a> RsaPssPrivateKey<'a> {
222        ///Create a new [`RsaPssPrivateKey`] from a byte slice and a public key.
223        ///
224        /// Returns an error if the length of the byte slice is not equal to the
225        /// key/modulus size.
226        pub fn new(pk: &'a RsaPssPublicKey, d: &[u8]) -> Result<Self, Error> {
227            if pk.n.len() != d.len() {
228                return Err(Error::InvalidKey);
229            }
230            Ok(Self { pk, d: d.into() })
231        }
232
233        /// Sign the provided `msg` with the `private_key` using the `hash_algorithm`
234        /// and `salt`.
235        ///
236        /// Returns an error if any of the inputs are invalid and the signature as byte
237        /// array.
238        pub fn sign(
239            &self,
240            hash_algorithm: DigestAlgorithm,
241            salt: &[u8],
242            msg: &[u8],
243        ) -> Result<RsaPssSignature, Error> {
244            if salt.len() > (u32::MAX as usize) || msg.len() > (u32::MAX as usize) {
245                return Err(Error::InputTooLarge);
246            }
247
248            let key_len = self.d.len();
249            let mut signature = vec![0; key_len];
250            let key_size_bits = (key_len as u32) * 8;
251
252            unsafe {
253                let s_key = Hacl_RSAPSS_new_rsapss_load_skey(
254                    key_size_bits,
255                    E_BITS,
256                    key_size_bits,
257                    self.pk.n.as_ptr() as _,
258                    E.as_ptr() as _,
259                    self.d.as_ptr() as _,
260                );
261
262                if !Hacl_RSAPSS_rsapss_sign(
263                    rsa_pss_digest(hash_algorithm),
264                    key_size_bits,
265                    E_BITS,
266                    key_size_bits,
267                    s_key,
268                    salt.len() as u32,
269                    salt.as_ptr() as _,
270                    msg.len() as u32,
271                    msg.as_ptr() as _,
272                    signature.as_mut_ptr(),
273                ) {
274                    hacl_free(s_key as _);
275                    return Err(Error::SigningError);
276                }
277                hacl_free(s_key as _);
278            }
279            Ok(RsaPssSignature { value: signature })
280        }
281    }
282}
283
284impl Ed25519Signature {
285    /// Generate a signature from the raw 64 bytes.
286    pub fn from_bytes(signature: [u8; 64]) -> Self {
287        Self { signature }
288    }
289
290    /// Generate a signature from the raw bytes slice.
291    ///
292    /// Returns an error if the slice has legnth != 64.
293    pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
294        Ok(Self {
295            signature: bytes.try_into().map_err(|_| Error::InvalidSignature)?,
296        })
297    }
298
299    /// Get the signature as the raw 64 bytes.
300    pub fn as_bytes(&self) -> &[u8; 64] {
301        &self.signature
302    }
303}
304
305impl EcDsaP256Signature {
306    /// Generate a signature from the raw values r and s.
307    pub fn from_raw(r: [u8; 32], s: [u8; 32], alg: Algorithm) -> Self {
308        Self { r, s, alg }
309    }
310
311    /// Generate a signature from the raw values r || s.
312    pub fn from_bytes(signature_bytes: [u8; 64], alg: Algorithm) -> Self {
313        Self {
314            r: signature_bytes[0..32].try_into().unwrap(),
315            s: signature_bytes[32..].try_into().unwrap(),
316            alg,
317        }
318    }
319
320    /// Get the signature as the two raw 32 bytes `(r, s)`.
321    pub fn as_bytes(&self) -> (&[u8; 32], &[u8; 32]) {
322        (&self.r, &self.s)
323    }
324}
325
326/// Prepare the nonce for EcDSA and validate the key
327fn ecdsa_p256_sign_prep(
328    private_key: &[u8],
329    rng: &mut (impl CryptoRng + RngCore),
330) -> Result<(ecdh::p256::PrivateKey, [u8; 32]), Error> {
331    let private_key = p256::validate_scalar_slice(private_key).map_err(|_| Error::SigningError)?;
332
333    let mut nonce = [0u8; 32];
334    loop {
335        rng.try_fill_bytes(&mut nonce)
336            .map_err(|_| Error::SigningError)?;
337        // Make sure it's a valid nonce.
338        if p256::validate_scalar_slice(&nonce).is_ok() {
339            break;
340        }
341    }
342
343    Ok((private_key, nonce))
344}
345
346/// Wrap EcDSA result into a signature
347fn ecdsa_p256_sign_post(signature: [u8; 64], alg: Algorithm) -> Result<Signature, Error> {
348    Ok(Signature::EcDsaP256(EcDsaP256Signature {
349        r: signature[..32]
350            .try_into()
351            .map_err(|_| Error::SigningError)?,
352        s: signature[32..]
353            .try_into()
354            .map_err(|_| Error::SigningError)?,
355        alg,
356    }))
357}
358
359fn into_signing_error(_e: impl Into<hacl::Error>) -> Error {
360    Error::SigningError
361}
362
363/// Sign the `payload` with the given [`Algorithm`] and `private_key`.
364///
365/// Returns the [`Signature`] or an [`Error::SigningError`].
366pub fn sign(
367    alg: Algorithm,
368    payload: &[u8],
369    private_key: &[u8],
370    rng: &mut (impl CryptoRng + RngCore),
371) -> Result<Signature, Error> {
372    let signature = match alg {
373        Algorithm::EcDsaP256(DigestAlgorithm::Sha256) => {
374            let (private_key, nonce) = ecdsa_p256_sign_prep(private_key, rng)?;
375            ecdsa_p256_sign_post(
376                p256::ecdsa::sign_sha256(payload, private_key.as_ref(), &nonce)
377                    .map_err(into_signing_error)?,
378                alg,
379            )?
380        }
381        Algorithm::EcDsaP256(DigestAlgorithm::Sha384) => {
382            let (private_key, nonce) = ecdsa_p256_sign_prep(private_key, rng)?;
383            ecdsa_p256_sign_post(
384                p256::ecdsa::sign_sha384(payload, private_key.as_ref(), &nonce)
385                    .map_err(into_signing_error)?,
386                alg,
387            )?
388        }
389        Algorithm::EcDsaP256(DigestAlgorithm::Sha512) => {
390            let (private_key, nonce) = ecdsa_p256_sign_prep(private_key, rng)?;
391            ecdsa_p256_sign_post(
392                p256::ecdsa::sign_sha512(payload, private_key.as_ref(), &nonce)
393                    .map_err(into_signing_error)?,
394                alg,
395            )?
396        }
397        Algorithm::Ed25519 => {
398            let signature = ed25519::sign(
399                payload,
400                private_key.try_into().map_err(|_| Error::SigningError)?,
401            )
402            .map_err(into_signing_error)?;
403            Signature::Ed25519(Ed25519Signature { signature })
404        }
405        Algorithm::RsaPss(_) => {
406            todo!()
407        }
408    };
409
410    Ok(signature)
411}
412
413fn into_verify_error(_e: impl Into<hacl::Error>) -> Error {
414    Error::InvalidSignature
415}
416
417/// Prepare the public key for EcDSA
418fn ecdsa_p256_verify_prep(public_key: &[u8]) -> Result<[u8; 64], Error> {
419    if public_key.is_empty() {
420        return Err(Error::SigningError);
421    }
422
423    // Parse the public key.
424    let pk = if let Ok(pk) = p256::uncompressed_to_coordinates(public_key) {
425        pk
426    } else {
427        // Might be uncompressed
428        if let Ok(pk) = p256::compressed_to_coordinates(public_key) {
429            pk
430        } else {
431            // Might be a simple concatenation
432            public_key.try_into().map_err(|_| Error::InvalidSignature)?
433        }
434    };
435
436    p256::validate_point(ecdh::p256::PublicKey(pk))
437        .map(|()| pk)
438        .map_err(into_verify_error)
439}
440
441/// Verify the `payload` and `signature` with the `public_key`.
442///
443/// Return `()` or [`Error::InvalidSignature`].
444pub fn verify(payload: &[u8], signature: &Signature, public_key: &[u8]) -> Result<(), Error> {
445    match signature {
446        Signature::EcDsaP256(signature) => match signature.alg {
447            Algorithm::EcDsaP256(DigestAlgorithm::Sha256) => {
448                let pk = ecdsa_p256_verify_prep(public_key)?;
449                p256::ecdsa::verify_sha256(payload, &pk, &signature.r, &signature.s)
450            }
451            Algorithm::EcDsaP256(DigestAlgorithm::Sha384) => {
452                let pk = ecdsa_p256_verify_prep(public_key)?;
453                p256::ecdsa::verify_sha384(payload, &pk, &signature.r, &signature.s)
454            }
455            Algorithm::EcDsaP256(DigestAlgorithm::Sha512) => {
456                let pk = ecdsa_p256_verify_prep(public_key)?;
457                p256::ecdsa::verify_sha512(payload, &pk, &signature.r, &signature.s)
458            }
459            _ => Err(p256::Error::InvalidInput),
460        }
461        .map_err(into_verify_error),
462        Signature::Ed25519(signature) => {
463            let public_key = public_key.try_into().map_err(|_| Error::InvalidSignature)?;
464            ed25519::verify(payload, public_key, &signature.signature).map_err(into_verify_error)
465        }
466        Signature::RsaPss(_) => todo!(),
467    }
468}
469
470/// Generate a fresh key pair.
471///
472/// The function returns the (secret key, public key) tuple, or an [`Error`].
473pub fn key_gen(
474    alg: Algorithm,
475    rng: &mut (impl CryptoRng + Rng),
476) -> Result<(Vec<u8>, Vec<u8>), Error> {
477    match alg {
478        Algorithm::EcDsaP256(_) => {
479            ecdh::key_gen(ecdh::Algorithm::P256, rng).map_err(|_| Error::KeyGenError)
480        }
481        Algorithm::Ed25519 => {
482            const LIMIT: usize = 100;
483            let mut sk = [0u8; 32];
484            for _ in 0..LIMIT {
485                rng.try_fill_bytes(&mut sk)
486                    .map_err(|_| Error::KeyGenError)?;
487
488                // We don't want a 0 key.
489                if sk.iter().all(|&b| b == 0) {
490                    sk = [0u8; 32];
491                    continue;
492                }
493
494                // We clamp the key already to make sure it can't be misused.
495                sk[0] = sk[0] & 248u8;
496                sk[31] = sk[31] & 127u8;
497                sk[31] = sk[31] | 64u8;
498
499                break;
500            }
501            let pk = ed25519::secret_to_public(&sk);
502
503            Ok((sk.to_vec(), pk.to_vec()))
504        }
505        Algorithm::RsaPss(_) => todo!(),
506    }
507}