From d05f6cecbaeda0be9eae6a80517c1839d581545e Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 17 Nov 2020 16:54:32 +0100 Subject: openpgp: Drop hash::Context in favor of a pub trait hash::Digest. --- ipc/src/keygrip.rs | 7 +- openpgp/src/cert.rs | 5 +- openpgp/src/crypto/ecdh.rs | 1 + openpgp/src/crypto/hash.rs | 163 ++++++++++++++++--------------------- openpgp/src/crypto/mem.rs | 1 + openpgp/src/crypto/mpi.rs | 23 ++++-- openpgp/src/crypto/s2k.rs | 1 + openpgp/src/packet/container.rs | 4 +- openpgp/src/packet/key.rs | 2 +- openpgp/src/packet/mdc.rs | 4 +- openpgp/src/packet/signature.rs | 6 +- openpgp/src/parse.rs | 6 +- openpgp/src/parse/hashed_reader.rs | 4 +- openpgp/src/serialize/stream.rs | 4 +- 14 files changed, 110 insertions(+), 121 deletions(-) diff --git a/ipc/src/keygrip.rs b/ipc/src/keygrip.rs index 1f4f3edf..968b975f 100644 --- a/ipc/src/keygrip.rs +++ b/ipc/src/keygrip.rs @@ -89,17 +89,16 @@ impl Keygrip { /// ``` pub fn of(key: &PublicKey) -> Result { use openpgp::crypto::hash; - use std::io::Write; use self::PublicKey::*; let mut hash = HashAlgorithm::SHA1.context().unwrap(); - fn hash_sexp_mpi(hash: &mut hash::Context, kind: char, prefix: &[u8], + fn hash_sexp_mpi(hash: &mut dyn hash::Digest, kind: char, prefix: &[u8], mpi: &MPI) { hash_sexp(hash, kind, prefix, mpi.value()); } - fn hash_sexp(hash: &mut hash::Context, kind: char, prefix: &[u8], + fn hash_sexp(hash: &mut dyn hash::Digest, kind: char, prefix: &[u8], buf: &[u8]) { write!(hash, "(1:{}{}:", @@ -109,7 +108,7 @@ impl Keygrip { write!(hash, ")").unwrap(); } - fn hash_ecc(hash: &mut hash::Context, curve: &Curve, q: &MPI) + fn hash_ecc(hash: &mut dyn hash::Digest, curve: &Curve, q: &MPI) { for (i, name) in "pabgnhq".chars().enumerate() { if i == 5 { diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs index bc274021..3876b8e1 100644 --- a/openpgp/src/cert.rs +++ b/openpgp/src/cert.rs @@ -148,7 +148,10 @@ use std::ops::{Deref, DerefMut}; use std::time; use crate::{ - crypto::Signer, + crypto::{ + Signer, + hash::Digest, + }, Error, Result, SignatureType, diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs index c203e397..84b8660e 100644 --- a/openpgp/src/crypto/ecdh.rs +++ b/openpgp/src/crypto/ecdh.rs @@ -12,6 +12,7 @@ use crate::vec_truncate; use crate::{Error, Result}; use crate::crypto::SessionKey; +use crate::crypto::hash::Digest; use crate::crypto::mem::Protected; use crate::crypto::mpi::{self, MPI}; use crate::key; diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs index 27641429..13645379 100644 --- a/openpgp/src/crypto/hash.rs +++ b/openpgp/src/crypto/hash.rs @@ -1,12 +1,35 @@ //! Cryptographic hash functions and hashing of OpenPGP data //! structures. //! -//! This module provides [`Context`] representing a hash function +//! This module provides trait [`Digest`] representing a hash function //! context independent of the cryptographic backend, as well as trait //! [`Hash`] that handles hashing of OpenPGP data structures. //! -//! [`Context`]: struct.Context.html +//! [`Digest`]: trait.Digest.html //! [`Hash`]: trait.Hash.html +//! +//! # Examples +//! +//! ```rust +//! # fn main() -> sequoia_openpgp::Result<()> { +//! use sequoia_openpgp::types::HashAlgorithm; +//! +//! // Create a context and feed data to it. +//! let mut ctx = HashAlgorithm::SHA512.context()?; +//! ctx.update(&b"The quick brown fox jumps over the lazy dog."[..]); +//! +//! // Extract the digest. +//! let mut digest = vec![0; ctx.digest_size()]; +//! ctx.digest(&mut digest); +//! +//! use sequoia_openpgp::fmt::hex; +//! assert_eq!(&hex::encode(digest), +//! "91EA1245F20D46AE9A037A989F54F1F7\ +//! 90F0A47607EEB8A14D12890CEA77A1BB\ +//! C6C7ED9CF205E67B7F2B8FD4C7DFD3A7\ +//! A8617E45F3C463D481C7E586C39AC1ED"); +//! # Ok(()) } +//! ``` use std::convert::TryFrom; @@ -31,7 +54,12 @@ use std::io::{self, Write}; const DUMP_HASHED_VALUES: Option<&str> = None; /// Hasher capable of calculating a digest for the input byte stream. -pub(crate) trait Digest: DynClone + Write + Send + Sync { +/// +/// This provides an abstract interface to the hash functions used in +/// OpenPGP. `Digest`s can be are created using [`HashAlgorithm::context`]. +/// +/// [`HashAlgorithm::context`]: ../../types/enum.HashAlgorithm.html#method.context +pub trait Digest: DynClone + Write + Send + Sync { /// Returns the algorithm. fn algo(&self) -> HashAlgorithm; @@ -49,59 +77,30 @@ pub(crate) trait Digest: DynClone + Write + Send + Sync { /// `digest` must be at least `self.digest_size()` bytes large, /// otherwise the digest will be truncated. fn digest(&mut self, digest: &mut [u8]) -> Result<()>; + + /// Finalizes the hash function and computes the digest. + fn into_digest(mut self) -> Result> + where Self: std::marker::Sized + { + let mut digest = vec![0u8; self.digest_size()]; + self.digest(&mut digest)?; + Ok(digest) + } } dyn_clone::clone_trait_object!(Digest); -/// State of a hash function. -/// -/// This provides an abstract interface to the hash functions used in -/// OpenPGP. `Context`s are created using [`HashAlgorithm::context`]. -/// -/// [`HashAlgorithm::context`]: ../../types/enum.HashAlgorithm.html#method.context -/// -/// # Examples -/// -/// ```rust -/// # fn main() -> sequoia_openpgp::Result<()> { -/// use sequoia_openpgp::types::HashAlgorithm; -/// -/// // Create a context and feed data to it. -/// let mut ctx = HashAlgorithm::SHA512.context()?; -/// ctx.update(&b"The quick brown fox jumps over the lazy dog."[..]); -/// -/// // Extract the digest. -/// let mut digest = vec![0; ctx.digest_size()]; -/// ctx.digest(&mut digest); -/// -/// use sequoia_openpgp::fmt::hex; -/// assert_eq!(&hex::encode(digest), -/// "91EA1245F20D46AE9A037A989F54F1F7\ -/// 90F0A47607EEB8A14D12890CEA77A1BB\ -/// C6C7ED9CF205E67B7F2B8FD4C7DFD3A7\ -/// A8617E45F3C463D481C7E586C39AC1ED"); -/// # Ok(()) } -/// ``` -#[derive(Clone)] -pub struct Context { - algo: HashAlgorithm, - ctx: Box, -} - -impl Context { - /// Returns the algorithm. - pub fn algo(&self) -> HashAlgorithm { - self.algo +impl Digest for Box { + fn algo(&self) -> HashAlgorithm { + self.as_ref().algo() } - - /// Size of the digest in bytes - pub fn digest_size(&self) -> usize { - self.ctx.digest_size() + fn digest_size(&self) -> usize { + self.as_ref().digest_size() } /// Writes data into the hash function. - pub fn update>(&mut self, data: D) { - self.ctx.update(data.as_ref()); + fn update(&mut self, data: &[u8]) { + self.as_mut().update(data) } /// Finalizes the hash function and writes the digest into the @@ -113,26 +112,8 @@ impl Context { /// otherwise the digest will be truncated. /// /// [`self.digest_size()`]: #method.digest_size - pub fn digest>(&mut self, mut digest: D) -> Result<()> { - self.ctx.digest(digest.as_mut()) - } - - /// Finalizes the hash function and computes the digest. - pub fn into_digest(mut self) -> Result> { - let mut digest = vec![0u8; self.digest_size()]; - self.digest(&mut digest)?; - Ok(digest) - } -} - -impl io::Write for Context { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.update(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) + fn digest(&mut self, digest: &mut [u8]) -> Result<()>{ + self.as_mut().digest(digest) } } @@ -146,19 +127,16 @@ impl HashAlgorithm { /// [`HashAlgorithm::is_supported`]. /// /// [`HashAlgorithm::is_supported`]: #method.is_supported - pub fn context(self) -> Result { - let hasher = match self { + pub fn context(self) -> Result> { + let hasher: Box = match self { HashAlgorithm::SHA1 => Box::new(crate::crypto::backend::sha1cd::build()), _ => self.new_hasher()?, }; - Ok(Context { - algo: self, - ctx: if let Some(prefix) = DUMP_HASHED_VALUES { - Box::new(HashDumper::new(hasher, prefix)) - } else { - hasher - }, + Ok(if let Some(prefix) = DUMP_HASHED_VALUES { + Box::new(HashDumper::new(hasher, prefix)) + } else { + hasher }) } } @@ -261,24 +239,24 @@ impl io::Write for HashDumper { /// [`Signature`'s hashing functions]: ../../packet/enum.Signature.html#hashing-functions pub trait Hash { /// Updates the given hash with this object. - fn hash(&self, hash: &mut Context); + fn hash(&self, hash: &mut dyn Digest); } impl Hash for UserID { - fn hash(&self, hash: &mut Context) { + fn hash(&self, hash: &mut dyn Digest) { let len = self.value().len() as u32; let mut header = [0; 5]; header[0] = 0xB4; header[1..5].copy_from_slice(&len.to_be_bytes()); - hash.update(header); + hash.update(&header); hash.update(self.value()); } } impl Hash for UserAttribute { - fn hash(&self, hash: &mut Context) { + fn hash(&self, hash: &mut dyn Digest) { let len = self.value().len() as u32; let mut header = [0; 5]; @@ -294,7 +272,7 @@ impl Hash for Key4 where P: key::KeyParts, R: key::KeyRole, { - fn hash(&self, hash: &mut Context) { + fn hash(&self, hash: &mut dyn Digest) { use crate::serialize::MarshalInto; // We hash 9 bytes plus the MPIs. But, the len doesn't @@ -330,7 +308,7 @@ impl Hash for Key4 } impl Hash for Signature { - fn hash(&self, hash: &mut Context) { + fn hash(&self, hash: &mut dyn Digest) { match self { Signature::V4(sig) => sig.hash(hash), } @@ -338,13 +316,13 @@ impl Hash for Signature { } impl Hash for Signature4 { - fn hash(&self, hash: &mut Context) { + fn hash(&self, hash: &mut dyn Digest) { self.fields.hash(hash); } } impl Hash for signature::SignatureFields { - fn hash(&self, hash: &mut Context) { + fn hash(&self, hash: &mut dyn Digest) { use crate::serialize::MarshalInto; // XXX: Annoyingly, we have no proper way of handling errors @@ -406,20 +384,20 @@ impl Hash for signature::SignatureFields { /// impl signature::SignatureFields { /// Computes the message digest of standalone signatures. - pub fn hash_standalone(&self, hash: &mut Context) + pub fn hash_standalone(&self, hash: &mut dyn Digest) { self.hash(hash); } /// Computes the message digest of timestamp signatures. - pub fn hash_timestamp(&self, hash: &mut Context) + pub fn hash_timestamp(&self, hash: &mut dyn Digest) { self.hash_standalone(hash); } /// Returns the message digest of the direct key signature over /// the specified primary key. - pub fn hash_direct_key

(&self, hash: &mut Context, + pub fn hash_direct_key

(&self, hash: &mut dyn Digest, key: &Key) where P: key::KeyParts, { @@ -429,7 +407,7 @@ impl signature::SignatureFields { /// Returns the message digest of the subkey binding over the /// specified primary key and subkey. - pub fn hash_subkey_binding(&self, hash: &mut Context, + pub fn hash_subkey_binding(&self, hash: &mut dyn Digest, key: &Key, subkey: &Key) where P: key::KeyParts, @@ -442,7 +420,7 @@ impl signature::SignatureFields { /// Returns the message digest of the primary key binding over the /// specified primary key and subkey. - pub fn hash_primary_key_binding(&self, hash: &mut Context, + pub fn hash_primary_key_binding(&self, hash: &mut dyn Digest, key: &Key, subkey: &Key) where P: key::KeyParts, @@ -453,7 +431,7 @@ impl signature::SignatureFields { /// Returns the message digest of the user ID binding over the /// specified primary key, user ID, and signature. - pub fn hash_userid_binding

(&self, hash: &mut Context, + pub fn hash_userid_binding

(&self, hash: &mut dyn Digest, key: &Key, userid: &UserID) where P: key::KeyParts, @@ -467,7 +445,7 @@ impl signature::SignatureFields { /// the specified primary key, user attribute, and signature. pub fn hash_user_attribute_binding

( &self, - hash: &mut Context, + hash: &mut dyn Digest, key: &Key, ua: &UserAttribute) where P: key::KeyParts, @@ -480,6 +458,7 @@ impl signature::SignatureFields { #[cfg(test)] mod test { + use super::*; use crate::Cert; use crate::parse::Parse; diff --git a/openpgp/src/crypto/mem.rs b/openpgp/src/crypto/mem.rs index 96f80483..f9979868 100644 --- a/openpgp/src/crypto/mem.rs +++ b/openpgp/src/crypto/mem.rs @@ -249,6 +249,7 @@ mod has_access_to_prekey { use lazy_static; use crate::types::{AEADAlgorithm, HashAlgorithm, SymmetricAlgorithm}; use crate::crypto::{aead, SessionKey}; + use crate::crypto::hash::Digest; use super::*; lazy_static::lazy_static! { diff --git a/openpgp/src/crypto/mpi.rs b/openpgp/src/crypto/mpi.rs index 8f9cfb2a..9eac133b 100644 --- a/openpgp/src/crypto/mpi.rs +++ b/openpgp/src/crypto/mpi.rs @@ -17,6 +17,7 @@ use std::fmt; use std::cmp::Ordering; +use std::io::Write; #[cfg(test)] use quickcheck::{Arbitrary, Gen}; @@ -237,7 +238,7 @@ impl fmt::Debug for MPI { } impl Hash for MPI { - fn hash(&self, hash: &mut hash::Context) { + fn hash(&self, hash: &mut dyn hash::Digest) { let len = self.bits() as u16; hash.update(&len.to_be_bytes()); @@ -545,8 +546,9 @@ impl PublicKey { } impl Hash for PublicKey { - fn hash(&self, hash: &mut hash::Context) { - self.serialize(hash).expect("hashing does not fail") + fn hash(&self, mut hash: &mut dyn hash::Digest) { + self.serialize(&mut hash as &mut dyn Write) + .expect("hashing does not fail") } } @@ -806,8 +808,9 @@ impl SecretKeyMaterial { } impl Hash for SecretKeyMaterial { - fn hash(&self, hash: &mut hash::Context) { - self.serialize(hash).expect("hashing does not fail") + fn hash(&self, mut hash: &mut dyn hash::Digest) { + self.serialize(&mut hash as &mut dyn Write) + .expect("hashing does not fail") } } @@ -930,8 +933,9 @@ impl Ciphertext { } impl Hash for Ciphertext { - fn hash(&self, hash: &mut hash::Context) { - self.serialize(hash).expect("hashing does not fail") + fn hash(&self, mut hash: &mut dyn hash::Digest) { + self.serialize(&mut hash as &mut dyn Write) + .expect("hashing does not fail") } } @@ -1021,8 +1025,9 @@ pub enum Signature { } impl Hash for Signature { - fn hash(&self, hash: &mut hash::Context) { - self.serialize(hash).expect("hashing does not fail") + fn hash(&self, mut hash: &mut dyn hash::Digest) { + self.serialize(&mut hash as &mut dyn Write) + .expect("hashing does not fail") } } diff --git a/openpgp/src/crypto/s2k.rs b/openpgp/src/crypto/s2k.rs index ecc6313e..93430810 100644 --- a/openpgp/src/crypto/s2k.rs +++ b/openpgp/src/crypto/s2k.rs @@ -11,6 +11,7 @@ use crate::Result; use crate::HashAlgorithm; use crate::crypto::Password; use crate::crypto::SessionKey; +use crate::crypto::hash::Digest; use std::fmt; diff --git a/openpgp/src/packet/container.rs b/openpgp/src/packet/container.rs index a06d84cc..cb96b85d 100644 --- a/openpgp/src/packet/container.rs +++ b/openpgp/src/packet/container.rs @@ -296,14 +296,14 @@ impl Container { /// Creates a hash context for hashing the body. pub(crate) // For parse.rs - fn make_body_hash() -> hash::Context { + fn make_body_hash() -> Box { CONTAINER_BODY_HASH.context() .expect("CONTAINER_BODY_HASH must be implemented") } /// Hashes content that has been streamed. pub(crate) // For parse.rs - fn set_body_hash(&mut self, mut h: hash::Context) { + fn set_body_hash(&mut self, mut h: Box) { self.body_digest.resize(h.digest_size(), 0); let _ = h.digest(&mut self.body_digest); } diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs index 34fbedc0..f705b60d 100644 --- a/openpgp/src/packet/key.rs +++ b/openpgp/src/packet/key.rs @@ -96,7 +96,7 @@ use quickcheck::{Arbitrary, Gen}; use crate::Error; use crate::cert::prelude::*; -use crate::crypto::{self, mem, mpi, hash::Hash}; +use crate::crypto::{self, mem, mpi, hash::{Hash, Digest}}; use crate::packet; use crate::packet::prelude::*; use crate::PublicKeyAlgorithm; diff --git a/openpgp/src/packet/mdc.rs b/openpgp/src/packet/mdc.rs index fdb6513e..9f07dafe 100644 --- a/openpgp/src/packet/mdc.rs +++ b/openpgp/src/packet/mdc.rs @@ -88,8 +88,8 @@ impl From<[u8; 20]> for MDC { } } -impl From for MDC { - fn from(mut hash: crypto::hash::Context) -> Self { +impl From> for MDC { + fn from(mut hash: Box) -> Self { let mut value : [u8; 20] = Default::default(); let _ = hash.digest(&mut value[..]); value.into() diff --git a/openpgp/src/packet/signature.rs b/openpgp/src/packet/signature.rs index ff952c7b..9128332d 100644 --- a/openpgp/src/packet/signature.rs +++ b/openpgp/src/packet/signature.rs @@ -126,7 +126,7 @@ use crate::Error; use crate::Result; use crate::crypto::{ mpi, - hash::{self, Hash}, + hash::{self, Hash, Digest}, Signer, }; use crate::KeyHandle; @@ -1424,7 +1424,7 @@ impl SignatureBuilder { /// [`set_signature_creation_time`]: #method.set_signature_creation_time /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time pub fn sign_hash(mut self, signer: &mut dyn Signer, - mut hash: hash::Context) + mut hash: Box) -> Result { self.hash_algo = hash.algo(); @@ -2312,7 +2312,7 @@ impl Signature { /// subkey binding signature (if appropriate), has the signing /// capability, etc. pub fn verify_hash(&mut self, key: &Key, - mut hash: hash::Context) + mut hash: Box) -> Result<()> where P: key::KeyParts, R: key::KeyRole, diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs index e31bb6d4..d25d4a73 100644 --- a/openpgp/src/parse.rs +++ b/openpgp/src/parse.rs @@ -717,7 +717,7 @@ pub(crate) struct SignatureGroup { ops_count: usize, /// The hash contexts. - pub(crate) hashes: Vec>, + pub(crate) hashes: Vec>>, } /// Controls line-ending normalization during hashing. @@ -1859,7 +1859,7 @@ impl OnePassSig3 { { if let Ok(ctx) = hash_algo.context() { cookie.sig_group_mut().hashes.push( - HashingMode::for_signature(ctx, typ) + HashingMode::for_signature(Box::new(ctx), typ) ); } } @@ -3226,7 +3226,7 @@ pub struct PacketParser<'a> { /// We compute a hashsum over the body to implement comparison on /// containers that have been streamed. - body_hash: Option, + body_hash: Option>, state: PacketParserState, } diff --git a/openpgp/src/parse/hashed_reader.rs b/openpgp/src/parse/hashed_reader.rs index a6aff9e7..bdaefe18 100644 --- a/openpgp/src/parse/hashed_reader.rs +++ b/openpgp/src/parse/hashed_reader.rs @@ -57,7 +57,7 @@ impl> HashedReader { /// Updates the given hash context normalizing line endings to "\r\n" /// on the fly. -pub(crate) fn hash_update_text(h: &mut crate::crypto::hash::Context, +pub(crate) fn hash_update_text(h: &mut dyn crate::crypto::hash::Digest, text: &[u8]) { let mut line = text; while ! line.is_empty() { @@ -271,7 +271,7 @@ impl> /// [`DetachedVerifier`]: ../parse/stream/struct.DetachedVerifier.html pub(crate) fn hash_buffered_reader(reader: R, algos: &[HashingMode]) - -> Result>> + -> Result>>> where R: BufferedReader, { let mut reader diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index 0cb96178..382ca86a 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -639,7 +639,7 @@ pub struct Signer<'a> { detached: bool, template: signature::SignatureBuilder, creation_time: Option, - hash: crypto::hash::Context, + hash: Box, cookie: Cookie, position: u64, } @@ -2077,7 +2077,7 @@ pub struct Encryptor<'a> { passwords: Vec, sym_algo: SymmetricAlgorithm, aead_algo: Option, - hash: crypto::hash::Context, + hash: Box, cookie: Cookie, } -- cgit v1.2.3