use super::bigint::BigInt;
use super::rsa::{RsaPublicKey, RsaSecretKey, rsa_decrypt_raw, rsa_encrypt_raw};
use crate::Hasher;
use crate::hash::ripemd160::Ripemd160;
use crate::hash::sha1::Sha1;
use crate::hash::sha3::{Sha3_256, Sha3_384, Sha3_512};
use crate::hash::sha256::Sha256;
use crate::hash::sha384::Sha384;
use crate::hash::sha512::Sha512;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum HashAlg {
Sha1,
Sha256,
Sha384,
Sha512,
Sha3_256,
Sha3_384,
Sha3_512,
Ripemd160,
}
impl HashAlg {
fn digest_info_prefix(&self) -> &'static [u8] {
match self {
HashAlg::Sha1 => &[
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
],
HashAlg::Sha256 => &[
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
0x04, 0x20,
],
HashAlg::Sha384 => &[
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00,
0x04, 0x30,
],
HashAlg::Sha512 => &[
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00,
0x04, 0x40,
],
HashAlg::Sha3_256 => &[
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00,
0x04, 0x20,
],
HashAlg::Sha3_384 => &[
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00,
0x04, 0x30,
],
HashAlg::Sha3_512 => &[
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, 0x00,
0x04, 0x40,
],
HashAlg::Ripemd160 => &[
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14,
],
}
}
fn hash_len(&self) -> usize {
match self {
HashAlg::Sha1 | HashAlg::Ripemd160 => 20,
HashAlg::Sha256 | HashAlg::Sha3_256 => 32,
HashAlg::Sha384 | HashAlg::Sha3_384 => 48,
HashAlg::Sha512 | HashAlg::Sha3_512 => 64,
}
}
}
pub fn pkcs1v15_encrypt(pk: &RsaPublicKey, msg: &[u8], rng: &mut dyn FnMut(&mut [u8])) -> Vec<u8> {
let k = pk.modulus_byte_len();
assert!(
msg.len() <= k - 11,
"PKCS1v15 encrypt: message too long (max {} bytes, got {})",
k - 11,
msg.len()
);
let ps_len = k - msg.len() - 3;
let mut em = vec![0u8; k];
em[0] = 0x00;
em[1] = 0x02;
rng(&mut em[2..2 + ps_len]);
for b in em[2..2 + ps_len].iter_mut() {
while *b == 0 {
let mut tmp = [0u8; 1];
rng(&mut tmp);
*b = tmp[0];
}
}
em[2 + ps_len] = 0x00;
em[3 + ps_len..].copy_from_slice(msg);
let m = BigInt::from_be_bytes(&em);
let c = rsa_encrypt_raw(pk, &m);
c.to_be_bytes(k)
}
pub fn pkcs1v15_decrypt(sk: &RsaSecretKey, ct: &[u8]) -> Option<Vec<u8>> {
let k = sk.modulus_byte_len();
if ct.len() != k || k < 11 {
return None;
}
let c = BigInt::from_be_bytes(ct);
let m = rsa_decrypt_raw(sk, &c);
let em = m.to_be_bytes(k);
if em[0] != 0x00 || em[1] != 0x02 {
return None;
}
let mut sep = None;
for i in 2..em.len() {
if em[i] == 0x00 {
if i < 10 {
return None;
}
sep = Some(i);
break;
}
}
let sep = sep?;
Some(em[sep + 1..].to_vec())
}
pub fn pkcs1v15_sign(sk: &RsaSecretKey, hash: &[u8], hash_alg: HashAlg) -> Vec<u8> {
let k = sk.modulus_byte_len();
let prefix = hash_alg.digest_info_prefix();
let t_len = prefix.len() + hash_alg.hash_len();
assert!(hash.len() == hash_alg.hash_len(), "Hash length mismatch");
assert!(k >= t_len + 11, "Modulus too short for PKCS1v15 signature");
let ps_len = k - t_len - 3;
let mut em = vec![0u8; k];
em[0] = 0x00;
em[1] = 0x01;
for i in 0..ps_len {
em[2 + i] = 0xFF;
}
em[2 + ps_len] = 0x00;
em[3 + ps_len..3 + ps_len + prefix.len()].copy_from_slice(prefix);
em[3 + ps_len + prefix.len()..].copy_from_slice(hash);
let m = BigInt::from_be_bytes(&em);
let s = rsa_decrypt_raw(sk, &m); s.to_be_bytes(k)
}
pub fn pkcs1v15_verify(pk: &RsaPublicKey, hash: &[u8], hash_alg: HashAlg, sig: &[u8]) -> bool {
let k = pk.modulus_byte_len();
if sig.len() != k {
return false;
}
if hash.len() != hash_alg.hash_len() {
return false;
}
let s = BigInt::from_be_bytes(sig);
let m = rsa_encrypt_raw(pk, &s); let em = m.to_be_bytes(k);
let prefix = hash_alg.digest_info_prefix();
let t_len = prefix.len() + hash_alg.hash_len();
if k < t_len + 11 {
return false;
}
let ps_len = k - t_len - 3;
let mut expected = vec![0u8; k];
expected[0] = 0x00;
expected[1] = 0x01;
for i in 0..ps_len {
expected[2 + i] = 0xFF;
}
expected[2 + ps_len] = 0x00;
expected[3 + ps_len..3 + ps_len + prefix.len()].copy_from_slice(prefix);
expected[3 + ps_len + prefix.len()..].copy_from_slice(hash);
let mut diff = 0u8;
for (a, b) in em.iter().zip(expected.iter()) {
diff |= a ^ b;
}
diff == 0 && em.len() == expected.len()
}
pub fn pkcs1v15_sign_sha256(sk: &RsaSecretKey, message: &[u8]) -> Vec<u8> {
let hash = Sha256::hash(message);
pkcs1v15_sign(sk, &hash, HashAlg::Sha256)
}
pub fn pkcs1v15_verify_sha256(pk: &RsaPublicKey, message: &[u8], sig: &[u8]) -> bool {
let hash = Sha256::hash(message);
pkcs1v15_verify(pk, &hash, HashAlg::Sha256, sig)
}
macro_rules! convenience_pair {
($sign_fn:ident, $verify_fn:ident, $hasher:ty, $alg:expr, $doc:literal) => {
#[doc = $doc]
pub fn $sign_fn(sk: &RsaSecretKey, message: &[u8]) -> Vec<u8> {
let hash = <$hasher as Hasher>::hash(message);
pkcs1v15_sign(sk, &hash, $alg)
}
#[doc = $doc]
pub fn $verify_fn(pk: &RsaPublicKey, message: &[u8], sig: &[u8]) -> bool {
let hash = <$hasher as Hasher>::hash(message);
pkcs1v15_verify(pk, &hash, $alg, sig)
}
};
}
convenience_pair!(
pkcs1v15_sign_sha1,
pkcs1v15_verify_sha1,
Sha1,
HashAlg::Sha1,
"Convenience: hash a message with SHA-1, then sign / verify. \
**Legacy**: do not use for new designs; SHA-1 is collision-broken."
);
convenience_pair!(
pkcs1v15_sign_sha384,
pkcs1v15_verify_sha384,
Sha384,
HashAlg::Sha384,
"Convenience: hash a message with SHA-384, then sign / verify."
);
convenience_pair!(
pkcs1v15_sign_sha512,
pkcs1v15_verify_sha512,
Sha512,
HashAlg::Sha512,
"Convenience: hash a message with SHA-512, then sign / verify."
);
convenience_pair!(
pkcs1v15_sign_sha3_256,
pkcs1v15_verify_sha3_256,
Sha3_256,
HashAlg::Sha3_256,
"Convenience: hash a message with SHA3-256, then sign / verify."
);
convenience_pair!(
pkcs1v15_sign_sha3_384,
pkcs1v15_verify_sha3_384,
Sha3_384,
HashAlg::Sha3_384,
"Convenience: hash a message with SHA3-384, then sign / verify."
);
convenience_pair!(
pkcs1v15_sign_sha3_512,
pkcs1v15_verify_sha3_512,
Sha3_512,
HashAlg::Sha3_512,
"Convenience: hash a message with SHA3-512, then sign / verify."
);
convenience_pair!(
pkcs1v15_sign_ripemd160,
pkcs1v15_verify_ripemd160,
Ripemd160,
HashAlg::Ripemd160,
"Convenience: hash a message with RIPEMD-160, then sign / verify. \
**Legacy**: included for compatibility with older systems \
(Bitcoin, some 2000s X.509 CAs); not recommended for new designs."
);
#[cfg(test)]
mod tests {
use super::*;
fn test_rng() -> impl FnMut(&mut [u8]) {
let mut state: u64 = 0xdeadbeefcafebabe;
move |buf: &mut [u8]| {
for b in buf.iter_mut() {
state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
*b = (state >> 33) as u8;
}
}
}
#[test]
fn test_pkcs1v15_encrypt_decrypt_roundtrip() {
let mut rng = test_rng();
let (pk, sk) = super::super::rsa::rsa_keygen(512, &mut rng);
let msg = b"Hello, RSA!";
let ct = pkcs1v15_encrypt(&pk, msg, &mut rng);
let pt = pkcs1v15_decrypt(&sk, &ct).expect("decryption failed");
assert_eq!(&pt, msg);
}
#[test]
fn test_pkcs1v15_sign_verify_roundtrip() {
let mut rng = test_rng();
let (pk, sk) = super::super::rsa::rsa_keygen(512, &mut rng);
let message = b"Sign me!";
let sig = pkcs1v15_sign_sha256(&sk, message);
assert!(pkcs1v15_verify_sha256(&pk, message, &sig));
let mut bad_sig = sig.clone();
bad_sig[0] ^= 0xFF;
assert!(!pkcs1v15_verify_sha256(&pk, message, &bad_sig));
}
#[test]
fn pkcs1v15_all_supported_hashes_roundtrip() {
let mut rng = test_rng();
let (pk, sk) = super::super::rsa::rsa_keygen(1024, &mut rng);
let msg = b"hash flexibility test";
let sig = pkcs1v15_sign_sha1(&sk, msg);
assert!(pkcs1v15_verify_sha1(&pk, msg, &sig));
let sig = pkcs1v15_sign_sha256(&sk, msg);
assert!(pkcs1v15_verify_sha256(&pk, msg, &sig));
let sig = pkcs1v15_sign_sha384(&sk, msg);
assert!(pkcs1v15_verify_sha384(&pk, msg, &sig));
let sig = pkcs1v15_sign_sha512(&sk, msg);
assert!(pkcs1v15_verify_sha512(&pk, msg, &sig));
let sig = pkcs1v15_sign_sha3_256(&sk, msg);
assert!(pkcs1v15_verify_sha3_256(&pk, msg, &sig));
let sig = pkcs1v15_sign_sha3_384(&sk, msg);
assert!(pkcs1v15_verify_sha3_384(&pk, msg, &sig));
let sig = pkcs1v15_sign_sha3_512(&sk, msg);
assert!(pkcs1v15_verify_sha3_512(&pk, msg, &sig));
let sig = pkcs1v15_sign_ripemd160(&sk, msg);
assert!(pkcs1v15_verify_ripemd160(&pk, msg, &sig));
}
#[test]
fn pkcs1v15_hash_mismatch_rejected() {
let mut rng = test_rng();
let (pk, sk) = super::super::rsa::rsa_keygen(1024, &mut rng);
let msg = b"hash mismatch test";
let sig256 = pkcs1v15_sign_sha256(&sk, msg);
assert!(pkcs1v15_verify_sha256(&pk, msg, &sig256));
assert!(!pkcs1v15_verify_sha512(&pk, msg, &sig256));
assert!(!pkcs1v15_verify_sha3_256(&pk, msg, &sig256));
let sig512 = pkcs1v15_sign_sha512(&sk, msg);
assert!(pkcs1v15_verify_sha512(&pk, msg, &sig512));
assert!(!pkcs1v15_verify_sha256(&pk, msg, &sig512));
let sig3_256 = pkcs1v15_sign_sha3_256(&sk, msg);
assert!(pkcs1v15_verify_sha3_256(&pk, msg, &sig3_256));
assert!(!pkcs1v15_verify_sha256(&pk, msg, &sig3_256));
}
#[test]
fn hashalg_lengths_agree_with_hasher_output_len() {
assert_eq!(HashAlg::Sha1.hash_len(), <Sha1 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Sha256.hash_len(), <Sha256 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Sha384.hash_len(), <Sha384 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Sha512.hash_len(), <Sha512 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Sha3_256.hash_len(), <Sha3_256 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Sha3_384.hash_len(), <Sha3_384 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Sha3_512.hash_len(), <Sha3_512 as Hasher>::OUTPUT_LEN);
assert_eq!(HashAlg::Ripemd160.hash_len(), <Ripemd160 as Hasher>::OUTPUT_LEN);
}
}