6 releases (3 breaking)
0.5.0  Nov 24, 2020 

0.4.1  Aug 23, 2020 
0.4.0  Jun 21, 2020 
0.2.1  Feb 17, 2020 
0.1.0  Apr 4, 2019 
#1183 in Cryptography
972 downloads per month
Used in 6 crates
(5 directly)
22KB
244 lines
RSAFDH
RSAFDH is a is provably secure blindsigning signature scheme that uses RSA and a full domain hash.
This project implements two RSAFDH signature schemes:

A regular signature scheme with Full Domain Hash (FDH) padding.

A blind signature scheme that that supports blindsigning to keep the message being signed secret from the signer.
Caveats

When using the blind signature scheme, the signing key should only be used as part of RSAFDH blindsigning. Key reuse for encryption or as part of other protocols can result in key disclosure.

This project and it's dependencies have not undergone a security audit. The 1.0 version will not be released until it does. If you are interested in performing a security audit, please see this ticket.
Regular signature scheme example
use rsa_fdh;
use rsa::{RSAPrivateKey, RSAPublicKey};
use sha2::{Sha256, Digest};
// Set up rng and message
let mut rng = rand::thread_rng();
let message = b"NEVER GOING TO GIVE YOU UP";
// Create the keys
let signer_priv_key = RSAPrivateKey::new(&mut rng, 256)?;
let signer_pub_key: RSAPublicKey = signer_priv_key.clone().into();
// Apply a standard digest to the message
let mut hasher = Sha256::new();
hasher.input(message);
let digest = hasher.result();
// Obtain a signture
let signature = rsa_fdh::sign::<Sha256, _>(&mut rng, &signer_priv_key, &digest)?;
// Verify the signature
rsa_fdh::verify::<Sha256, _>(&signer_pub_key, &digest, &signature)?;
Blind signature scheme example
use rsa_fdh;
use rsa::{RSAPrivateKey, RSAPublicKey};
use sha2::{Sha256, Digest};
// Set up rng and message
let mut rng = rand::thread_rng();
let message = b"NEVER GOING TO GIVE YOU UP";
// Create the keys
let signer_priv_key = RSAPrivateKey::new(&mut rng, 256)?;
let signer_pub_key: RSAPublicKey = signer_priv_key.clone().into();
// Hash the contents of the message with a Full Domain Hash, getting the digest
let digest = blind::hash_message::<Sha256, _>(&signer_pub_key, message)?;
// Get the blinded digest and the secret unblinder
let (blinded_digest, unblinder) = blind::blind(&mut rng, &signer_pub_key, &digest);
// Send the blindeddigest to the signer and get their signature
let blind_signature = blind::sign(&mut rng, &signer_priv_key, &blinded_digest)?;
// Unblind the signature
let signature = blind::unblind(&signer_pub_key, &blind_signature, &unblinder);
// Verify the signature
blind::verify(&signer_pub_key, &digest, &signature)?;
Protocol Description
A full domain hash (FDH) is constructed as follows:
FDH(π, πΌπ) = H(π β π β πΌπ + 0) β H(π β π β πΌπ + 1) β H(π β π β πΌπ + 2) ...
Where:
 π is the message
 H is any hash function
 π is the signing key's public modulus
 πΌπ is a onebyte initialization vector
The message is hashed (along with π and πΌπ + incrementing suffix) in rounds until the length of the hash is greater than or equal to the length of π. The hash is truncated as needed to produce the digest π· with the same length as π.
π· must also be smaller than π, so we increment πΌπ until we find a π· that is smaller than π.
Pseudocode:
fn generate_digest(message, public_key):
fdh = create_fdh(algo=sha256, length=public_key.bitlen())
iv = 0
digest = fdh(message, iv)
while digest.as_int() > public_key.n():
iv++
digest = fdh(message, iv)
return digest
The while
loop finishes within a minimal number of iterations because π generally occurs around (2^bitlen) / 2
.
Two signature schemes are supported:

In the regular signature scheme, the signer applies the FDH before signing the message.

In the blindsignature scheme, the sender applies the FDH to the message before blinding the resulting digest and sending it to the signer, who signs the blinded digest directly. The signer must not reuse their private keys for encryption outside of the RSAFDH blindsignature protocol.
Blinding, unblinding, signing and verification are done in the usual way for RSA.
Contributors
Dependencies
~9MB
~166K SLoC