1use 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
15pub trait Scheme {
17 const SIZE: usize;
19 type Digest: 'static + Digest + DynDigest + AssociatedOid + Send + Sync;
21 type Padding: SignatureScheme;
23
24 fn padding() -> Self::Padding;
26}
27
28pub trait Parameters: VerifySignature {
30 fn modulus(&self) -> Vec<u8>;
32
33 fn exponent(&self) -> Vec<u8>;
35
36 fn size(&self) -> usize;
38}
39
40pub struct Pss256;
42pub struct Pss384;
44pub struct Pss512;
46pub struct Pkcs256;
48pub struct Pkcs384;
50pub 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
107pub struct VerifyingKey<S: Scheme> {
109 pub(crate) key: rsa::RsaPublicKey,
111 pub(crate) scheme: PhantomData<S>,
113}
114
115pub struct SigningKey<S: Scheme> {
117 pub(crate) key: rsa::RsaPrivateKey,
119 pub(crate) scheme: PhantomData<S>,
121}
122
123impl<S: Scheme> VerifyingKey<S> {
124 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}