summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorIgor Matuszewski <igor@sequoia-pgp.org>2020-04-10 01:39:20 +0200
committerIgor Matuszewski <igor@sequoia-pgp.org>2020-06-22 11:57:07 +0200
commit61c66c3df5b12f79102eccddf479f58c1a3bdd63 (patch)
tree226e4dfa536e2c78a9e66a616831deb34e91b054 /openpgp
parentc8c207e931f204e5746eaff7dd57382048d26492 (diff)
openpgp: Move Nettle hashing impls to the backend module
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/Cargo.toml1
-rw-r--r--openpgp/src/crypto/backend/nettle.rs1
-rw-r--r--openpgp/src/crypto/backend/nettle/hash.rs84
-rw-r--r--openpgp/src/crypto/hash.rs124
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);
}
}