feat: implement pkcs1v15 signature verification

This commit is contained in:
dignifiedquire 2018-07-24 22:04:41 +02:00
parent 4d46e98db7
commit f6f909d344
2 changed files with 82 additions and 1 deletions

View File

@ -108,6 +108,27 @@ impl RSAPublicKey {
)),
}
}
/// Verify a signed message.
/// `hashed`must be the result of hashing the input using the hashing function
/// passed in through `hash`.
/// If the message is valid `Ok(())` is returned, otherwiese an `Err` indicating failure.
pub fn verify<H: Hash>(
&self,
padding: PaddingScheme,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()> {
match padding {
PaddingScheme::PKCS1v15 => pkcs1v15::verify(self, hash, hashed, sig),
PaddingScheme::PSS => unimplemented!("not yet implemented"),
_ => Err(format_err!(
"invalid padding scheme for decryption: {:?}",
padding
)),
}
}
}
impl<'a> PublicKey for &'a RSAPublicKey {

View File

@ -100,6 +100,44 @@ pub fn sign<R: Rng, H: Hash>(
Ok(em)
}
/// Verifies an RSA PKCS#1 v1.5 signature.
#[inline]
pub fn verify<H: Hash, K: PublicKey>(
pub_key: &K,
hash: Option<&H>,
hashed: &[u8],
sig: &[u8],
) -> Result<()> {
let (hash_len, prefix) = hash_info(hash, hashed.len())?;
let t_len = prefix.len() + hash_len;
let k = pub_key.size();
if k < t_len + 11 {
return Err(format_err!("verification error"));
}
let c = BigUint::from_bytes_be(sig);
let m = key::encrypt(pub_key, &c).to_bytes_be();
let em = key::left_pad(&m, k);
// EM = 0x00 || 0x01 || PS || 0x00 || T
let mut ok = em[0].ct_eq(&0u8);
ok = ok & em[1].ct_eq(&1u8);
ok = ok & em[k - hash_len..k].ct_eq(hashed);
ok = ok & em[k - t_len..k - hash_len].ct_eq(&prefix);
ok = ok & em[k - t_len - 1].ct_eq(&0u8);
for el in em.iter().skip(2).take(k - t_len - 3) {
ok = ok & el.ct_eq(&0xff)
}
if ok.unwrap_u8() != 1 {
return Err(format_err!("verification error"));
}
Ok(())
}
#[inline]
fn hash_info<H: Hash>(hash: Option<&H>, digest_len: usize) -> Result<(usize, Vec<u8>)> {
match hash {
@ -321,6 +359,25 @@ mod tests {
}
}
#[test]
fn test_verify_pkcs1v15() {
let priv_key = get_private_key();
let tests = [[
"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
]];
let pub_key: RSAPublicKey = priv_key.into();
for test in &tests {
let digest = Sha1::digest(test[0].as_bytes()).to_vec();
let sig = hex::decode(test[1]).unwrap();
pub_key
.verify(PaddingScheme::PKCS1v15, Some(&Hashes::SHA1), &digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_unpadded_signature() {
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
@ -332,6 +389,9 @@ mod tests {
.unwrap();
assert_eq!(expected_sig, sig);
// TODO: verify sig once implemented
let pub_key: RSAPublicKey = priv_key.into();
pub_key
.verify::<Hashes>(PaddingScheme::PKCS1v15, None, msg, &sig)
.expect("failed to verify");
}
}