rsa_fdh/
blind.rs

1//! A blind signature scheme that that supports blind-signing to keep the message being signed secret from the signer.
2//!
3//! The private key **must not** be used in any other way other than blind-signing.
4//! See [the wikipedia article on blind-signing](https://en.wikipedia.org/wiki/Blind_signature#Dangers_of_RSA_blind_signing).
5//!
6//! ### Example
7//! ```
8//! use rsa_fdh::blind;
9//! use rsa::{RSAPrivateKey, RSAPublicKey};
10//! use sha2::{Sha256, Digest};
11//!
12//! // Set up rng and message
13//! let mut rng = rand::thread_rng();
14//! let message = b"NEVER GOING TO GIVE YOU UP";
15//!
16//! // Create the keys
17//! let signer_priv_key = RSAPrivateKey::new(&mut rng, 2048).unwrap();
18//! let signer_pub_key: RSAPublicKey = signer_priv_key.clone().into();
19//!
20//! // Hash the contents of the message with a Full Domain Hash, getting the digest
21//! let digest = blind::hash_message::<Sha256, _>(&signer_pub_key, message).unwrap();
22//!
23//! // Get the blinded digest and the secret unblinder
24//! let (blinded_digest, unblinder) = blind::blind(&mut rng, &signer_pub_key, &digest);
25//!
26//! // Send the blinded-digest to the signer and get their signature
27//! let blind_signature = blind::sign(&mut rng, &signer_priv_key, &blinded_digest).unwrap();
28//!
29//! // Unblind the signature
30//! let signature = blind::unblind(&signer_pub_key, &blind_signature, &unblinder);
31//!
32//! // Verify the signature
33//! let ok = blind::verify(&signer_pub_key, &digest, &signature);
34//! assert!(ok.is_ok());
35//! ```
36
37pub use crate::common::sign_hashed as sign;
38pub use crate::common::verify_hashed as verify;
39use fdh::Digest;
40use num_bigint::BigUint;
41use rand::Rng;
42use rsa::internals;
43use rsa::PublicKey;
44
45/// Hash the message as a Full Domain Hash
46pub fn hash_message<H: Digest + Clone, P: PublicKey>(
47    signer_public_key: &P,
48    message: &[u8],
49) -> Result<Vec<u8>, crate::Error>
50where
51    H::OutputSize: Clone,
52{
53    let (result, _iv) = crate::common::hash_message::<H, P>(signer_public_key, message)?;
54    Ok(result)
55}
56
57/// Blind the given digest, returning the blinded digest and the unblinding factor.
58pub fn blind<R: Rng, P: PublicKey>(rng: &mut R, pub_key: P, digest: &[u8]) -> (Vec<u8>, Vec<u8>) {
59    let c = BigUint::from_bytes_be(digest);
60    let (c, unblinder) = internals::blind::<R, P>(rng, &pub_key, &c);
61    (c.to_bytes_be(), unblinder.to_bytes_be())
62}
63
64/// Unblind the given signature, producing a signature that also signs the unblided digest.
65pub fn unblind(pub_key: impl PublicKey, blinded_sig: &[u8], unblinder: &[u8]) -> Vec<u8> {
66    let blinded_sig = BigUint::from_bytes_be(blinded_sig);
67    let unblinder = BigUint::from_bytes_be(unblinder);
68    let unblinded = internals::unblind(pub_key, &blinded_sig, &unblinder);
69    unblinded.to_bytes_be()
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::blind;
75    use crate::Error;
76    use rsa::PublicKeyParts;
77    use rsa::{RSAPrivateKey, RSAPublicKey};
78    use sha2::Sha256;
79
80    #[test]
81    fn blind_test() -> Result<(), Error> {
82        // Stage 1: Setup
83        // --------------
84        let mut rng = rand::thread_rng();
85        let message = b"NEVER GOING TO GIVE YOU UP";
86
87        // Create the keys
88        // Note: Uses INSECURE 256 bit key for quick testing
89        let signer_priv_key = RSAPrivateKey::new(&mut rng, 256).unwrap();
90        let signer_pub_key =
91            RSAPublicKey::new(signer_priv_key.n().clone(), signer_priv_key.e().clone()).unwrap();
92
93        // Do this a bunch so that we get a good sampling of possibe digests.
94        for _ in 0..500 {
95            // Stage 2: Blind Signing
96            // ----------------------
97
98            // Hash the contents of the message, getting the digest
99            let digest = blind::hash_message::<Sha256, _>(&signer_pub_key, message)?;
100
101            // Get the blinded digest and the unblinder
102            let (blinded_digest, unblinder) = blind::blind(&mut rng, &signer_pub_key, &digest);
103
104            // Send the blinded-digest to the signer and get their signature
105            let blind_signature = blind::sign(&mut rng, &signer_priv_key, &blinded_digest)?;
106
107            // Assert the the blind signature does not validate against the orignal digest.
108            assert!(blind::verify(&signer_pub_key, &digest, &blind_signature).is_err());
109
110            // Unblind the signature
111            let signature = blind::unblind(&signer_pub_key, &blind_signature, &unblinder);
112
113            // Stage 3: Verification
114            // ---------------------
115
116            // Rehash the message using the iv
117            let check_digest = blind::hash_message::<Sha256, _>(&signer_pub_key, message)?;
118
119            // Check that the signature matches on the unblinded signature and the rehashed digest.
120            blind::verify(&signer_pub_key, &check_digest, &signature)?;
121        }
122
123        Ok(())
124    }
125
126    #[test]
127    fn error_test() -> Result<(), Error> {
128        // Stage 1: Setup
129        // --------------
130        let mut rng = rand::thread_rng();
131        let message = b"NEVER GOING TO GIVE YOU UP";
132
133        // Create the keys
134        let key_1 = RSAPrivateKey::new(&mut rng, 256).unwrap();
135        let public_1 = key_1.to_public_key();
136        let digest_1 = blind::hash_message::<Sha256, _>(&public_1, message)?;
137        let (blinded_digest_1, unblinder_1) = blind::blind(&mut rng, &public_1, &digest_1);
138        let blind_signature_1 = blind::sign(&mut rng, &key_1, &blinded_digest_1)?;
139        let signature_1 = blind::unblind(&public_1, &blind_signature_1, &unblinder_1);
140
141        let key_2 = RSAPrivateKey::new(&mut rng, 512).unwrap();
142        let public_2 = key_2.to_public_key();
143        let digest_2 = blind::hash_message::<Sha256, _>(&public_2, message)?;
144        let (blinded_digest_2, unblinder_2) = blind::blind(&mut rng, &public_2, &digest_2);
145        let blind_signature_2 = blind::sign(&mut rng, &key_2, &blinded_digest_2)?;
146        let signature_2 = blind::unblind(&public_2, &blind_signature_2, &unblinder_2);
147
148        // Assert that everything is differnet
149        assert!(digest_1 != digest_2);
150        assert!(blinded_digest_1 != blinded_digest_2);
151        assert!(unblinder_1 != unblinder_2);
152        assert!(blind_signature_1 != blind_signature_2);
153        assert!(signature_1 != signature_2);
154
155        // Assert that they don't cross validate
156        assert!(blind::sign(&mut rng, &key_1, &blinded_digest_2).is_err());
157        assert!(blind::verify(&public_1, &digest_1, &signature_2).is_err());
158        assert!(blind::verify(&public_1, &digest_2, &signature_1).is_err());
159        assert!(blind::verify(&public_1, &digest_2, &signature_2).is_err());
160        assert!(blind::verify(&public_2, &digest_1, &signature_1).is_err());
161        assert!(blind::verify(&public_2, &digest_1, &signature_2).is_err());
162        assert!(blind::verify(&public_2, &digest_2, &signature_1).is_err());
163
164        Ok(())
165    }
166}