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