ts_crypto/
rsa.rs

1//! RSA cryptography
2
3use core::marker::PhantomData;
4
5use const_oid::AssociatedOid;
6use digest::{Digest, DynDigest};
7use rsa::{
8    BoxedUint, Pkcs1v15Sign, Pss,
9    traits::{PublicKeyParts, SignatureScheme},
10};
11use sha2::{Sha256, Sha384, Sha512};
12
13use crate::{SignMessage, ToVerifier, VerifySignature};
14
15/// An RSA scheme
16pub trait Scheme {
17    /// The modulus size in bytes
18    const SIZE: usize;
19    /// The digest algorithm
20    type Digest: 'static + Digest + DynDigest + AssociatedOid + Send + Sync;
21    /// The signature padding
22    type Padding: SignatureScheme;
23
24    /// Create an instance of the padding for this scheme.
25    fn padding() -> Self::Padding;
26}
27
28/// RSA key parameters
29pub trait Parameters: VerifySignature {
30    /// Get the key's modulus
31    fn modulus(&self) -> Vec<u8>;
32
33    /// Get the key's exponent
34    fn exponent(&self) -> Vec<u8>;
35
36    /// Get the key's size
37    fn size(&self) -> usize;
38}
39
40/// 256-byte RSA key using `PSS` padding
41pub struct Pss256;
42/// 384-byte RSA key using `PSS` padding
43pub struct Pss384;
44/// 512-byte RSA key using `PSS` padding
45pub struct Pss512;
46/// 256-byte RSA key using PKCS1v1.5 padding
47pub struct Pkcs256;
48/// 384-byte RSA key using PKCS1v1.5 padding
49pub struct Pkcs384;
50/// 512-byte RSA key using PKCS1v1.5 padding
51pub struct Pkcs512;
52impl Scheme for Pss256 {
53    const SIZE: usize = 256;
54    type Digest = Sha256;
55    type Padding = Pss;
56
57    fn padding() -> Self::Padding {
58        Self::Padding::new::<Self::Digest>()
59    }
60}
61impl Scheme for Pss384 {
62    const SIZE: usize = 384;
63    type Digest = Sha384;
64    type Padding = Pss;
65
66    fn padding() -> Self::Padding {
67        Self::Padding::new::<Self::Digest>()
68    }
69}
70impl Scheme for Pss512 {
71    const SIZE: usize = 512;
72    type Digest = Sha512;
73    type Padding = Pss;
74
75    fn padding() -> Self::Padding {
76        Self::Padding::new::<Self::Digest>()
77    }
78}
79impl Scheme for Pkcs256 {
80    const SIZE: usize = 256;
81    type Digest = Sha256;
82    type Padding = Pkcs1v15Sign;
83
84    fn padding() -> Self::Padding {
85        Self::Padding::new::<Self::Digest>()
86    }
87}
88impl Scheme for Pkcs384 {
89    const SIZE: usize = 384;
90    type Digest = Sha384;
91    type Padding = Pkcs1v15Sign;
92
93    fn padding() -> Self::Padding {
94        Self::Padding::new::<Self::Digest>()
95    }
96}
97impl Scheme for Pkcs512 {
98    const SIZE: usize = 512;
99    type Digest = Sha512;
100    type Padding = Pkcs1v15Sign;
101
102    fn padding() -> Self::Padding {
103        Self::Padding::new::<Self::Digest>()
104    }
105}
106
107/// An RSA verifying key
108pub struct VerifyingKey<S: Scheme> {
109    /// The inner key
110    pub(crate) key: rsa::RsaPublicKey,
111    /// The RSA scheme
112    pub(crate) scheme: PhantomData<S>,
113}
114
115/// An RSA signing key
116pub struct SigningKey<S: Scheme> {
117    /// The inner key
118    pub(crate) key: rsa::RsaPrivateKey,
119    /// The RSA scheme
120    pub(crate) scheme: PhantomData<S>,
121}
122
123impl<S: Scheme> VerifyingKey<S> {
124    /// Create an RSA key from its parameters
125    pub fn from_parameters(modulus: &[u8], exponent: &[u8]) -> Option<Self> {
126        let modulus = BoxedUint::from_be_slice_vartime(modulus);
127        let exponent = BoxedUint::from_be_slice_vartime(exponent);
128        let key = rsa::RsaPublicKey::new(modulus, exponent).ok()?;
129        if key.size() != S::SIZE {
130            return None;
131        }
132        Some(Self {
133            key,
134            scheme: PhantomData,
135        })
136    }
137}
138impl<S: Scheme> Parameters for VerifyingKey<S> {
139    fn modulus(&self) -> Vec<u8> {
140        self.key.n_bytes().to_vec()
141    }
142
143    fn exponent(&self) -> Vec<u8> {
144        self.key.e_bytes().to_vec()
145    }
146
147    fn size(&self) -> usize {
148        S::SIZE
149    }
150}
151
152impl<S: Scheme> VerifySignature for VerifyingKey<S> {
153    fn verifies_signature(&self, signature: &[u8], message: &[u8]) -> bool {
154        let hash = S::Digest::digest(message);
155        let scheme = S::padding();
156        self.key.verify(scheme, &hash, signature).is_ok()
157    }
158}
159
160impl<S: Scheme> SignMessage for SigningKey<S> {
161    fn sign(&self, message: &[u8]) -> Vec<u8> {
162        let hash = S::Digest::digest(message);
163        self.key
164            .sign(S::padding(), &hash)
165            .expect("signing should not fail")
166            .to_vec()
167    }
168}
169
170impl<S: Scheme> ToVerifier for SigningKey<S> {
171    type Key = VerifyingKey<S>;
172
173    fn verifying_key(&self) -> Self::Key {
174        Self::Key {
175            key: self.key.to_public_key(),
176            scheme: PhantomData,
177        }
178    }
179}