diff --git a/Cargo.toml b/Cargo.toml index 7120c307..f0383b61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,16 +35,16 @@ digest = "^0.10" generic-array = "^0.14" hex = "^0.4" log = "0.4.6" -md-5 = "^0.10" +md-5 = { version = "^0.10.5", features = ["oid"] } nom = "^4.2" num-derive = "0.3.0" num-traits = "0.2.6" rand = "0.8" -ripemd = "^0.1" -rsa = "^0.6.0" -sha1 = "^0.10" -sha2 = "^0.10" -sha3 = "0.10" +ripemd = { version = "^0.1.3", features = ["oid"] } +rsa = { version = "^0.7.0", features = ["hazmat"] } +sha1 = { version = "^0.10.5", features = ["oid"] } +sha2 = { version = "^0.10.6", features = ["oid"] } +sha3 = { version = "^0.10.5", features = ["oid"] } signature = "1.3.0" smallvec = "1.6.1" thiserror = "1.0.9" diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 6601c051..392f7ace 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -1,14 +1,11 @@ use std::boxed::Box; -use std::convert::TryInto; - -use rsa::Hash; use digest::Digest; use md5::Md5; use ripemd::Ripemd160; use sha1::Sha1; -use crate::errors::{Error, Result}; +use crate::errors::Result; /// Available hash algorithms. /// Ref: https://tools.ietf.org/html/rfc4880.html#section-9.4 @@ -38,26 +35,6 @@ impl Default for HashAlgorithm { } } -impl TryInto for HashAlgorithm { - type Error = Error; - - fn try_into(self) -> Result { - match self { - HashAlgorithm::None => Err(format_err!("none")), - HashAlgorithm::MD5 => Ok(Hash::MD5), - HashAlgorithm::SHA1 => Ok(Hash::SHA1), - HashAlgorithm::RIPEMD160 => Ok(Hash::RIPEMD160), - HashAlgorithm::SHA2_256 => Ok(Hash::SHA2_256), - HashAlgorithm::SHA2_384 => Ok(Hash::SHA2_384), - HashAlgorithm::SHA2_512 => Ok(Hash::SHA2_512), - HashAlgorithm::SHA2_224 => Ok(Hash::SHA2_224), - HashAlgorithm::SHA3_256 => Ok(Hash::SHA3_256), - HashAlgorithm::SHA3_512 => Ok(Hash::SHA3_512), - HashAlgorithm::Private10 => unsupported_err!("Private10 should not be used"), - } - } -} - /// Trait to work around the fact that the `Digest` trait from rustcrypto can not /// be used as `Box`. pub trait Hasher: std::io::Write { diff --git a/src/crypto/rsa.rs b/src/crypto/rsa.rs index 750387ea..3cd52e25 100644 --- a/src/crypto/rsa.rs +++ b/src/crypto/rsa.rs @@ -1,15 +1,25 @@ -use std::convert::TryInto; - use num_bigint::traits::ModInverse; use num_bigint::BigUint; use rand::{CryptoRng, Rng}; use rsa::padding::PaddingScheme; +use rsa::pkcs1v15::{Signature as RsaSignature, SigningKey, VerifyingKey}; use rsa::{PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey}; use crate::crypto::HashAlgorithm; use crate::errors::Result; use crate::types::{Mpi, PlainSecretParams, PublicParams}; +use digest::{const_oid::AssociatedOid, Digest}; +use md5::Md5; +use ripemd::Ripemd160; +use sha1::Sha1; +use sha2::{Sha224, Sha256, Sha384, Sha512}; +use sha3::{Sha3_256, Sha3_512}; +use signature::hazmat::{PrehashSigner, PrehashVerifier}; +use signature::Signature; + +const MAX_KEY_SIZE: usize = 16384; + /// RSA decryption using PKCS1v15 padding. pub fn decrypt(priv_key: &RsaPrivateKey, mpis: &[Mpi], _fingerprint: &[u8]) -> Result> { // rsa consist of exactly one mpi @@ -28,7 +38,11 @@ pub fn encrypt( e: &[u8], plaintext: &[u8], ) -> Result>> { - let key = RsaPublicKey::new(BigUint::from_bytes_be(n), BigUint::from_bytes_be(e))?; + let key = RsaPublicKey::new_with_max_size( + BigUint::from_bytes_be(n), + BigUint::from_bytes_be(e), + MAX_KEY_SIZE, + )?; let data = key.encrypt(rng, PaddingScheme::new_pkcs1v15_encrypt(), plaintext)?; Ok(vec![data]) @@ -64,19 +78,64 @@ pub fn generate_key( )) } +fn verify_int(key: RsaPublicKey, hashed: &[u8], signature: &RsaSignature) -> Result<()> +where + D: Digest + AssociatedOid, +{ + VerifyingKey::::new_with_prefix(key) + .verify_prehash(hashed, &signature) + .map_err(Into::into) +} + +fn sign_int(key: RsaPrivateKey, digest: &[u8]) -> Result +where + D: Digest + AssociatedOid, +{ + SigningKey::::new_with_prefix(key) + .sign_prehash(digest) + .map_err(Into::into) +} + /// Verify a RSA, PKCS1v15 padded signature. pub fn verify(n: &[u8], e: &[u8], hash: HashAlgorithm, hashed: &[u8], sig: &[u8]) -> Result<()> { - let key = RsaPublicKey::new(BigUint::from_bytes_be(n), BigUint::from_bytes_be(e))?; - let rsa_hash: Option = hash.try_into().ok(); + let signature = Signature::from_bytes(sig)?; + let key = RsaPublicKey::new_with_max_size( + BigUint::from_bytes_be(n), + BigUint::from_bytes_be(e), + MAX_KEY_SIZE, + )?; - key.verify(PaddingScheme::new_pkcs1v15_sign(rsa_hash), hashed, sig) - .map_err(Into::into) + match hash { + HashAlgorithm::None => Err(format_err!("none")), + HashAlgorithm::MD5 => verify_int::(key, hashed, &signature), + HashAlgorithm::RIPEMD160 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA1 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA2_224 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA2_256 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA2_384 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA2_512 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA3_256 => verify_int::(key, hashed, &signature), + HashAlgorithm::SHA3_512 => verify_int::(key, hashed, &signature), + HashAlgorithm::Private10 => unsupported_err!("Private10 should not be used"), + } + .map_err(Into::into) } /// Sign using RSA, with PKCS1v15 padding. pub fn sign(key: &RsaPrivateKey, hash: HashAlgorithm, digest: &[u8]) -> Result>> { - let rsa_hash: Option = hash.try_into().ok(); - let sig = key.sign(PaddingScheme::new_pkcs1v15_sign(rsa_hash), digest)?; + let sig = match hash { + HashAlgorithm::None => return Err(format_err!("none")), + HashAlgorithm::MD5 => sign_int::(key.clone(), digest), + HashAlgorithm::RIPEMD160 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA1 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA2_224 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA2_256 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA2_384 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA2_512 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA3_256 => sign_int::(key.clone(), digest), + HashAlgorithm::SHA3_512 => sign_int::(key.clone(), digest), + HashAlgorithm::Private10 => unsupported_err!("Private10 should not be used"), + }?; - Ok(vec![sig]) + Ok(vec![sig.to_vec()]) } diff --git a/src/errors.rs b/src/errors.rs index 62a92a74..229978d6 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -60,8 +60,8 @@ pub enum Error { ParseIntError(#[from] std::num::ParseIntError), #[error("Invalid Packet Content {0:?}")] InvalidPacketContent(Box), - #[error("Ed25519 {0:?}")] - Ed25519SignatureError(#[from] SignatureError), + #[error("Signature {0:?}")] + SignatureError(#[from] SignatureError), #[error("Modification Detection Code error")] MdcError, } @@ -95,7 +95,7 @@ impl Error { Error::Utf8Error(_) => 23, Error::ParseIntError(_) => 24, Error::InvalidPacketContent(_) => 25, - Error::Ed25519SignatureError(_) => 26, + Error::SignatureError(_) => 26, Error::MdcError => 27, } } diff --git a/src/types/params/plain_secret.rs b/src/types/params/plain_secret.rs index a738f7cd..ceb332b8 100644 --- a/src/types/params/plain_secret.rs +++ b/src/types/params/plain_secret.rs @@ -129,7 +129,7 @@ impl<'a> PlainSecretParamsRef<'a> { e.into(), d.into(), vec![p.into(), q.into()], - ); + )?; secret_key.validate()?; Ok(SecretKeyRepr::RSA(secret_key)) }