1use crate::{
12 algorithms::pss::{sign_into, sign_with_rng_into},
13 errors::{Error, Result},
14 key::GenericRsaPrivateKey,
15 traits::{
16 modular::{ModulusParams, Pow, PowBoundedExp},
17 PublicKeyParts, UnsignedModularInt,
18 },
19};
20use core::fmt;
21use core::marker::PhantomData;
22use digest::{Digest, FixedOutputReset};
23use rand_core::TryCryptoRng;
24use zeroize::Zeroize;
25
26pub struct GenericSigningKey<D, T, M>
36where
37 D: Digest,
38 T: UnsignedModularInt + Zeroize,
39 M: ModulusParams<Modulus = T>,
40{
41 pub(super) inner: GenericRsaPrivateKey<T, M>,
42 pub(super) salt_len: usize,
43 pub(super) phantom: PhantomData<D>,
44}
45
46impl<D, T, M> fmt::Debug for GenericSigningKey<D, T, M>
49where
50 D: Digest,
51 T: UnsignedModularInt + Zeroize,
52 M: ModulusParams<Modulus = T>,
53 GenericRsaPrivateKey<T, M>: fmt::Debug,
54{
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.debug_struct("GenericSigningKey")
57 .field("inner", &self.inner)
58 .field("salt_len", &self.salt_len)
59 .finish()
60 }
61}
62
63#[cfg(feature = "alloc")]
68impl<D, T, M> Clone for GenericSigningKey<D, T, M>
69where
70 D: Digest,
71 T: UnsignedModularInt + Zeroize + Clone,
72 M: ModulusParams<Modulus = T> + Clone,
73 M::MontgomeryForm: Clone,
74{
75 fn clone(&self) -> Self {
76 Self {
77 inner: self.inner.clone(),
78 salt_len: self.salt_len,
79 phantom: PhantomData,
80 }
81 }
82}
83
84#[cfg(not(feature = "alloc"))]
85impl<D, T, M> Clone for GenericSigningKey<D, T, M>
86where
87 D: Digest,
88 T: UnsignedModularInt + Zeroize + Clone,
89 M: ModulusParams<Modulus = T> + Clone,
90{
91 fn clone(&self) -> Self {
92 Self {
93 inner: self.inner.clone(),
94 salt_len: self.salt_len,
95 phantom: PhantomData,
96 }
97 }
98}
99
100impl<D, T, M> GenericSigningKey<D, T, M>
101where
102 D: Digest,
103 T: UnsignedModularInt + Zeroize,
104 M: ModulusParams<Modulus = T>,
105{
106 pub fn new(key: GenericRsaPrivateKey<T, M>) -> Self {
109 Self {
110 inner: key,
111 salt_len: <D as Digest>::output_size(),
112 phantom: PhantomData,
113 }
114 }
115
116 pub fn new_with_salt_len(key: GenericRsaPrivateKey<T, M>, salt_len: usize) -> Self {
118 Self {
119 inner: key,
120 salt_len,
121 phantom: PhantomData,
122 }
123 }
124
125 pub fn salt_len(&self) -> usize {
127 self.salt_len
128 }
129}
130
131impl<D, T, M> AsRef<GenericRsaPrivateKey<T, M>> for GenericSigningKey<D, T, M>
134where
135 D: Digest,
136 T: UnsignedModularInt + Zeroize,
137 M: ModulusParams<Modulus = T>,
138{
139 fn as_ref(&self) -> &GenericRsaPrivateKey<T, M> {
140 &self.inner
141 }
142}
143
144impl<D, T, M> GenericSigningKey<D, T, M>
148where
149 D: Digest + FixedOutputReset,
150 T: UnsignedModularInt + Zeroize + crate::traits::modular::TryRandomMod,
151 T::Bytes: Zeroize,
152 M: ModulusParams<Modulus = T> + crate::traits::modular::CtModulusParams,
153 M::MontgomeryForm: Pow<M>
154 + PowBoundedExp<M>
155 + crate::traits::modular::InvertCt<M>
156 + crate::traits::modular::MulCt<M>,
157{
158 pub fn try_sign_with_rng_into<'sig, R: TryCryptoRng + ?Sized>(
168 &self,
169 rng: &mut R,
170 msg: &[u8],
171 em_storage: &mut [u8],
172 sig_storage: &'sig mut [u8],
173 salt_storage: &mut [u8],
174 ) -> Result<&'sig [u8]> {
175 let digest = D::digest(msg);
176 self.try_sign_prehash_with_rng_into(
177 rng,
178 digest.as_ref(),
179 em_storage,
180 sig_storage,
181 salt_storage,
182 )
183 }
184
185 pub fn try_sign_prehash_with_rng_into<'sig, R: TryCryptoRng + ?Sized>(
193 &self,
194 rng: &mut R,
195 prehash: &[u8],
196 em_storage: &mut [u8],
197 sig_storage: &'sig mut [u8],
198 salt_storage: &mut [u8],
199 ) -> Result<&'sig [u8]> {
200 if prehash.len() != <D as Digest>::output_size() {
201 return Err(Error::InputNotHashed);
202 }
203 let salt = salt_storage
204 .get_mut(..self.salt_len)
205 .ok_or(Error::OutputBufferTooSmall)?;
206 rng.try_fill_bytes(salt).map_err(|_| Error::Rng)?;
207 let mut hash = D::new();
208 sign_with_rng_into(
209 rng,
210 self.inner.n_params(),
211 crate::traits::keys::PrivateKeyParts::d(&self.inner),
212 self.inner.e(),
213 prehash,
214 salt,
215 self.inner.size(),
216 &mut hash,
217 em_storage,
218 sig_storage,
219 )
220 }
221}
222
223impl<D, T, M> GenericSigningKey<D, T, M>
228where
229 D: Digest + FixedOutputReset,
230 T: UnsignedModularInt + Zeroize,
231 T::Bytes: Zeroize,
232 M: ModulusParams<Modulus = T> + crate::traits::modular::CtModulusParams,
233 M::MontgomeryForm: Pow<M> + PowBoundedExp<M>,
234{
235 pub fn try_sign_prehash_with_salt_into<'sig>(
243 &self,
244 prehash: &[u8],
245 salt: &[u8],
246 em_storage: &mut [u8],
247 sig_storage: &'sig mut [u8],
248 ) -> Result<&'sig [u8]> {
249 if prehash.len() != <D as Digest>::output_size() {
250 return Err(Error::InputNotHashed);
251 }
252 if salt.len() != self.salt_len {
253 return Err(Error::InvalidArguments);
254 }
255 let mut hash = D::new();
256 sign_into(
257 self.inner.n_params(),
258 crate::traits::keys::PrivateKeyParts::d(&self.inner),
259 self.inner.e(),
260 prehash,
261 salt,
262 self.inner.size(),
263 &mut hash,
264 em_storage,
265 sig_storage,
266 )
267 }
268}
269
270impl<D, T, M> Zeroize for GenericSigningKey<D, T, M>
274where
275 D: Digest,
276 T: UnsignedModularInt + Zeroize,
277 M: ModulusParams<Modulus = T>,
278{
279 fn zeroize(&mut self) {
280 self.inner.zeroize();
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 #[test]
295 #[cfg(feature = "encoding")]
296 fn signing_key_try_sign_with_rng_into_round_trip() {
297 use crate::pss::{Signature, SigningKey, VerifyingKey};
298 use crate::RsaPrivateKey;
299 use pkcs1::DecodeRsaPrivateKey;
300 use rand::rngs::ChaCha8Rng;
301 use rand_core::SeedableRng;
302 use sha2::Sha256;
303 use signature::Verifier;
304
305 const PRIV_KEY_PKCS1_PEM: &str =
306 include_str!("../../tests/examples/pkcs1/rsa2048-priv.pem");
307
308 let priv_key = RsaPrivateKey::from_pkcs1_pem(PRIV_KEY_PKCS1_PEM).unwrap();
309 let signing_key = SigningKey::<Sha256>::new(priv_key.clone());
310 let verifying_key = VerifyingKey::<Sha256>::new(priv_key.to_public_key());
311
312 let msg: &[u8] = b"blinded pss sign test message";
313 let mut rng = ChaCha8Rng::from_seed([42; 32]);
314
315 let mut em_storage = [0u8; 256];
318 let mut sig_storage = [0u8; 256];
319 let mut salt_storage = [0u8; 32];
320 let sig_slice = signing_key
321 .try_sign_with_rng_into(
322 &mut rng,
323 msg,
324 &mut em_storage,
325 &mut sig_storage,
326 &mut salt_storage,
327 )
328 .unwrap();
329 assert_eq!(sig_slice.len(), 256);
330
331 let sig = Signature::try_from(sig_slice).unwrap();
332 verifying_key.verify(msg, &sig).unwrap();
333 }
334}