1use digest::{Digest, Update};
2use fdh::{FullDomainHash, VariableOutput};
3use num_bigint::BigUint;
4use rand::Rng;
5use rsa::errors::Error as RSAError;
6use rsa::internals;
7use rsa::{PublicKey, PublicKeyParts, RSAPrivateKey};
8use subtle::ConstantTimeEq;
9use thiserror::Error;
10
11#[derive(Debug, Error)]
13pub enum Error {
14 #[error("rsa-fdh: digest big-endian numeric value is too large")]
15 DigestTooLarge,
16 #[error("rsa-fdh: digest is incorrectly sized")]
17 DigestIncorrectSize,
18 #[error("rsa-fdh: verification failed")]
19 Verification,
20 #[error("rsa-fdh: public key modulus is too large")]
21 ModulusTooLarge,
22 #[error("rsa-fdh: rsa error: {}", 0)]
23 RSAError(RSAError),
24}
25
26pub fn hash_message<H: Digest + Clone, P: PublicKey>(
28 signer_public_key: &P,
29 message: &[u8],
30) -> Result<(Vec<u8>, u8), Error>
31where
32 H::OutputSize: Clone,
33{
34 let size = signer_public_key.size();
35 let mut hasher = FullDomainHash::<H>::new(size).unwrap(); hasher.update(message);
37
38 let append = signer_public_key.n().to_bytes_be();
40 hasher.update(append);
41
42 let iv: u8 = 0;
43 let zero = BigUint::from(0u8);
44 let (digest, iv) = hasher
45 .results_between(
46 iv,
47 &zero,
48 &BigUint::from_bytes_be(&signer_public_key.n().to_bytes_be()),
49 )
50 .map_err(|_| Error::ModulusTooLarge)?;
51
52 Ok((digest, iv))
53}
54
55pub fn verify_hashed<K: PublicKey>(pub_key: &K, hashed: &[u8], sig: &[u8]) -> Result<(), Error> {
57 if hashed.len() != pub_key.size() {
58 return Err(Error::Verification);
59 }
60
61 let n = BigUint::from_bytes_be(&pub_key.n().to_bytes_be());
62
63 let m = BigUint::from_bytes_be(&hashed);
64 if m >= n {
65 return Err(Error::Verification);
66 }
67
68 let c = BigUint::from_bytes_be(sig);
69 let mut m = internals::encrypt(pub_key, &c).to_bytes_be();
70 if m.len() < hashed.len() {
71 m = left_pad(&m, hashed.len());
72 }
73
74 let ok = m.ct_eq(&hashed);
76
77 if ok.unwrap_u8() != 1 {
78 return Err(Error::Verification);
79 }
80
81 Ok(())
82}
83
84pub fn sign_hashed<R: Rng>(
86 rng: &mut R,
87 priv_key: &RSAPrivateKey,
88 hashed: &[u8],
89) -> Result<Vec<u8>, Error> {
90 if priv_key.size() < hashed.len() {
91 return Err(Error::DigestIncorrectSize);
92 }
93
94 let n = priv_key.n();
95 let m = BigUint::from_bytes_be(&hashed);
96
97 if m >= *n {
98 return Err(Error::DigestTooLarge);
99 }
100
101 let c = internals::decrypt_and_check(Some(rng), priv_key, &m)
102 .map_err(Error::RSAError)?
103 .to_bytes_be();
104
105 Ok(c)
106}
107
108pub fn left_pad(input: &[u8], size: usize) -> Vec<u8> {
110 let n = if input.len() > size {
111 size
112 } else {
113 input.len()
114 };
115
116 let mut out = vec![0u8; size];
117 out[size - n..].copy_from_slice(input);
118 out
119}