diff options
author | Igor Matuszewski <igor@sequoia-pgp.org> | 2020-04-10 01:39:20 +0200 |
---|---|---|
committer | Igor Matuszewski <igor@sequoia-pgp.org> | 2020-06-22 11:57:07 +0200 |
commit | 61c66c3df5b12f79102eccddf479f58c1a3bdd63 (patch) | |
tree | 226e4dfa536e2c78a9e66a616831deb34e91b054 /openpgp | |
parent | c8c207e931f204e5746eaff7dd57382048d26492 (diff) |
openpgp: Move Nettle hashing impls to the backend module
Diffstat (limited to 'openpgp')
-rw-r--r-- | openpgp/Cargo.toml | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle.rs | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/hash.rs | 84 | ||||
-rw-r--r-- | openpgp/src/crypto/hash.rs | 124 |
4 files changed, 136 insertions, 74 deletions
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml index 2b33b04e..f4c1d665 100644 --- a/openpgp/Cargo.toml +++ b/openpgp/Cargo.toml @@ -29,6 +29,7 @@ anyhow = "1" buffered-reader = { path = "../buffered-reader", version = "0.17", default-features = false } base64 = ">= 0.11, < 0.13" bzip2 = { version = "0.3.2", optional = true } +dyn-clone = "1" flate2 = { version = "1.0.1", optional = true } idna = "0.2" lalrpop-util = "0.17" diff --git a/openpgp/src/crypto/backend/nettle.rs b/openpgp/src/crypto/backend/nettle.rs index 73b37569..25fc64eb 100644 --- a/openpgp/src/crypto/backend/nettle.rs +++ b/openpgp/src/crypto/backend/nettle.rs @@ -5,6 +5,7 @@ use nettle::random::{Random, Yarrow}; pub mod aead; pub mod asymmetric; pub mod ecdh; +pub mod hash; /// Fills the given buffer with random data. pub fn random<B: AsMut<[u8]>>(mut buf: B) { diff --git a/openpgp/src/crypto/backend/nettle/hash.rs b/openpgp/src/crypto/backend/nettle/hash.rs new file mode 100644 index 00000000..12271762 --- /dev/null +++ b/openpgp/src/crypto/backend/nettle/hash.rs @@ -0,0 +1,84 @@ +use crate::crypto::hash::Digest; +use crate::{Error, Result}; +use crate::types::{HashAlgorithm}; + +impl<T: nettle::hash::Hash + Clone> Digest for T { + fn digest_size(&self) -> usize { + self.digest_size() + } + + fn update(&mut self, data: &[u8]) { + self.update(data); + } + + fn digest(&mut self, digest: &mut [u8]) { + self.digest(digest); + } +} + +impl HashAlgorithm { + /// Whether Sequoia supports this algorithm. + pub fn is_supported(self) -> bool { + match self { + HashAlgorithm::SHA1 => true, + HashAlgorithm::SHA224 => true, + HashAlgorithm::SHA256 => true, + HashAlgorithm::SHA384 => true, + HashAlgorithm::SHA512 => true, + HashAlgorithm::RipeMD => true, + HashAlgorithm::MD5 => true, + HashAlgorithm::Private(_) => false, + HashAlgorithm::Unknown(_) => false, + HashAlgorithm::__Nonexhaustive => unreachable!(), + } + } + + /// Creates a new hash context for this algorithm. + /// + /// # Errors + /// + /// Fails with `Error::UnsupportedHashAlgorithm` if Sequoia does + /// not support this algorithm. See + /// [`HashAlgorithm::is_supported`]. + /// + /// [`HashAlgorithm::is_supported`]: #method.is_supported + pub fn new_hasher(self) -> Result<Box<dyn Digest>> { + use nettle::hash::{Sha224, Sha256, Sha384, Sha512}; + use nettle::hash::insecure_do_not_use::{ + Sha1, + Md5, + Ripemd160, + }; + + match self { + HashAlgorithm::SHA1 => Ok(Box::new(Sha1::default())), + HashAlgorithm::SHA224 => Ok(Box::new(Sha224::default())), + HashAlgorithm::SHA256 => Ok(Box::new(Sha256::default())), + HashAlgorithm::SHA384 => Ok(Box::new(Sha384::default())), + HashAlgorithm::SHA512 => Ok(Box::new(Sha512::default())), + HashAlgorithm::MD5 => Ok(Box::new(Md5::default())), + HashAlgorithm::RipeMD => Ok(Box::new(Ripemd160::default())), + HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) => + Err(Error::UnsupportedHashAlgorithm(self).into()), + HashAlgorithm::__Nonexhaustive => unreachable!(), + } + } + + /// Returns the ASN.1 OID of this hash algorithm. + pub fn oid(self) -> Result<&'static [u8]> { + use nettle::rsa; + + match self { + HashAlgorithm::SHA1 => Ok(rsa::ASN1_OID_SHA1), + HashAlgorithm::SHA224 => Ok(rsa::ASN1_OID_SHA224), + HashAlgorithm::SHA256 => Ok(rsa::ASN1_OID_SHA256), + HashAlgorithm::SHA384 => Ok(rsa::ASN1_OID_SHA384), + HashAlgorithm::SHA512 => Ok(rsa::ASN1_OID_SHA512), + HashAlgorithm::MD5 => Ok(rsa::ASN1_OID_MD5), + HashAlgorithm::RipeMD => Ok(rsa::ASN1_OID_RIPEMD160), + HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) => + Err(Error::UnsupportedHashAlgorithm(self).into()), + HashAlgorithm::__Nonexhaustive => unreachable!(), + } + } +} diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs index 15e1e965..fce57572 100644 --- a/openpgp/src/crypto/hash.rs +++ b/openpgp/src/crypto/hash.rs @@ -2,6 +2,8 @@ use std::convert::TryFrom; +use dyn_clone::DynClone; + use crate::HashAlgorithm; use crate::packet::Key; use crate::packet::UserID; @@ -10,7 +12,6 @@ use crate::packet::key; use crate::packet::key::Key4; use crate::packet::Signature; use crate::packet::signature::{self, Signature4}; -use crate::Error; use crate::Result; use crate::types::Timestamp; @@ -21,6 +22,26 @@ use std::io::{self, Write}; // hashed to files /tmp/hash-N, where N is a number. const DUMP_HASHED_VALUES: Option<&str> = None; +/// Hasher capable of calculating a digest for the input byte stream. +pub trait Digest: DynClone { + /// Size of the digest in bytes + fn digest_size(&self) -> usize; + + /// Writes data into the hash function. + fn update(&mut self, data: &[u8]); + + /// Finalizes the hash function and writes the digest into the + /// provided slice. + /// + /// Resets the hash function contexts. + /// + /// `digest` must be at least `self.digest_size()` bytes large, + /// otherwise the digest will be truncated. + fn digest(&mut self, digest: &mut [u8]); +} + +dyn_clone::clone_trait_object!(Digest); + /// State of a hash function. /// /// This provides an abstract interface to the hash functions used in @@ -49,7 +70,7 @@ const DUMP_HASHED_VALUES: Option<&str> = None; #[derive(Clone)] pub struct Context { algo: HashAlgorithm, - ctx: Box<dyn nettle::hash::Hash>, + ctx: Box<dyn Digest>, } impl Context { @@ -92,22 +113,6 @@ impl io::Write for Context { } impl HashAlgorithm { - /// Whether Sequoia supports this algorithm. - pub fn is_supported(self) -> bool { - match self { - HashAlgorithm::SHA1 => true, - HashAlgorithm::SHA224 => true, - HashAlgorithm::SHA256 => true, - HashAlgorithm::SHA384 => true, - HashAlgorithm::SHA512 => true, - HashAlgorithm::RipeMD => true, - HashAlgorithm::MD5 => true, - HashAlgorithm::Private(_) => false, - HashAlgorithm::Unknown(_) => false, - HashAlgorithm::__Nonexhaustive => unreachable!(), - } - } - /// Creates a new hash context for this algorithm. /// /// # Errors @@ -118,64 +123,27 @@ impl HashAlgorithm { /// /// [`HashAlgorithm::is_supported`]: #method.is_supported pub fn context(self) -> Result<Context> { - use nettle::hash::{Sha224, Sha256, Sha384, Sha512}; - use nettle::hash::insecure_do_not_use::{ - Sha1, - Md5, - Ripemd160, - }; - - let c: Result<Box<dyn nettle::hash::Hash>> = match self { - HashAlgorithm::SHA1 => Ok(Box::new(Sha1::default())), - HashAlgorithm::SHA224 => Ok(Box::new(Sha224::default())), - HashAlgorithm::SHA256 => Ok(Box::new(Sha256::default())), - HashAlgorithm::SHA384 => Ok(Box::new(Sha384::default())), - HashAlgorithm::SHA512 => Ok(Box::new(Sha512::default())), - HashAlgorithm::MD5 => Ok(Box::new(Md5::default())), - HashAlgorithm::RipeMD => Ok(Box::new(Ripemd160::default())), - HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) => - Err(Error::UnsupportedHashAlgorithm(self).into()), - HashAlgorithm::__Nonexhaustive => unreachable!(), - }; - - c.map(|ctx| Context { - algo: self, - ctx: if let Some(prefix) = DUMP_HASHED_VALUES { - Box::new(HashDumper::new(ctx, prefix)) - } else { - ctx - }, - }) - } - - /// Returns the ASN.1 OID of this hash algorithm. - pub fn oid(self) -> Result<&'static [u8]> { - use nettle::rsa; - - match self { - HashAlgorithm::SHA1 => Ok(rsa::ASN1_OID_SHA1), - HashAlgorithm::SHA224 => Ok(rsa::ASN1_OID_SHA224), - HashAlgorithm::SHA256 => Ok(rsa::ASN1_OID_SHA256), - HashAlgorithm::SHA384 => Ok(rsa::ASN1_OID_SHA384), - HashAlgorithm::SHA512 => Ok(rsa::ASN1_OID_SHA512), - HashAlgorithm::MD5 => Ok(rsa::ASN1_OID_MD5), - HashAlgorithm::RipeMD => Ok(rsa::ASN1_OID_RIPEMD160), - HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) => - Err(Error::UnsupportedHashAlgorithm(self).into()), - HashAlgorithm::__Nonexhaustive => unreachable!(), - } + self.new_hasher() + .map(|hasher| Context { + algo: self, + ctx: if let Some(prefix) = DUMP_HASHED_VALUES { + Box::new(HashDumper::new(hasher, prefix)) + } else { + hasher + }, + }) } } struct HashDumper { - h: Box<dyn nettle::hash::Hash>, + hasher: Box<dyn Digest>, sink: File, filename: String, written: usize, } impl HashDumper { - fn new(h: Box<dyn nettle::hash::Hash>, prefix: &str) -> Self { + fn new(hasher: Box<dyn Digest>, prefix: &str) -> Self { let mut n = 0; let mut filename; let sink = loop { @@ -189,7 +157,7 @@ impl HashDumper { }; eprintln!("HashDumper: Writing to {}...", &filename); HashDumper { - h, + hasher, sink, filename, written: 0, @@ -197,6 +165,17 @@ impl HashDumper { } } +impl Clone for HashDumper { + fn clone(&self) -> HashDumper { + // We only ever create instances of HashDumper when debugging. + // Whenever we're cloning an instance, just open another file for + // inspection. + let prefix = DUMP_HASHED_VALUES + .expect("cloning a HashDumper but DUMP_HASHED_VALUES wasn't specified"); + HashDumper::new(self.hasher.clone(), prefix) + } +} + impl Drop for HashDumper { fn drop(&mut self) { eprintln!("HashDumper: Wrote {} bytes to {}...", self.written, @@ -204,20 +183,17 @@ impl Drop for HashDumper { } } -impl nettle::hash::Hash for HashDumper { +impl Digest for HashDumper { fn digest_size(&self) -> usize { - self.h.digest_size() + self.hasher.digest_size() } fn update(&mut self, data: &[u8]) { - self.h.update(data); + self.hasher.update(data); self.sink.write_all(data).unwrap(); self.written += data.len(); } fn digest(&mut self, digest: &mut [u8]) { - self.h.digest(digest); - } - fn box_clone(&self) -> Box<dyn nettle::hash::Hash> { - Box::new(Self::new(self.h.box_clone(), &DUMP_HASHED_VALUES.unwrap())) + self.hasher.digest(digest); } } |