diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2019-07-02 16:11:25 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2019-07-02 16:11:25 +0200 |
commit | 9761b660b508d9440b192616f70c1a2d45cbbcb9 (patch) | |
tree | e2539088fc683564fad4ca1f29a94f00387477fe /openpgp/src/crypto | |
parent | a5548dc2e4db5b4a5469e7b320f37f89e32bb1b3 (diff) |
openpgp: Introduce an abstraction for hash contexts.
- See #302.
Diffstat (limited to 'openpgp/src/crypto')
-rw-r--r-- | openpgp/src/crypto/hash.rs | 70 | ||||
-rw-r--r-- | openpgp/src/crypto/mem.rs | 6 | ||||
-rw-r--r-- | openpgp/src/crypto/mod.rs | 4 | ||||
-rw-r--r-- | openpgp/src/crypto/mpis.rs | 13 | ||||
-rw-r--r-- | openpgp/src/crypto/s2k.rs | 2 |
5 files changed, 69 insertions, 26 deletions
diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs index 625cb5c8..b9d7170b 100644 --- a/openpgp/src/crypto/hash.rs +++ b/openpgp/src/crypto/hash.rs @@ -15,12 +15,50 @@ use nettle; use nettle::Hash as NettleHash; use std::fs::{File, OpenOptions}; -use std::io::Write; +use std::io::{self, Write}; // If set to e.g. Some("/tmp/hash"), we will dump everything that is // hashed to files /tmp/hash-N, where N is a number. const DUMP_HASHED_VALUES: Option<&str> = None; +/// State of a hash function. +#[derive(Clone)] +pub struct Context(Box<nettle::Hash>); + +impl Context { + /// Size of the digest in bytes + pub fn digest_size(&self) -> usize { + self.0.digest_size() + } + + /// Writes data into the hash function. + pub fn update<D: AsRef<[u8]>>(&mut self, data: D) { + self.0.update(data.as_ref()); + } + + /// 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. + pub fn digest<D: AsMut<[u8]>>(&mut self, mut digest: D) { + self.0.digest(digest.as_mut()); + } +} + +impl io::Write for Context { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.update(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + impl HashAlgorithm { /// Whether Sequoia supports this algorithm. pub fn is_supported(self) -> bool { @@ -46,7 +84,7 @@ impl HashAlgorithm { /// [`HashAlgorithm::is_supported`]. /// /// [`HashAlgorithm::is_supported`]: #method.is_supported - pub fn context(self) -> Result<Box<nettle::Hash>> { + pub fn context(self) -> Result<Context> { use nettle::hash::*; use nettle::hash::insecure_do_not_use::Sha1; @@ -63,11 +101,11 @@ impl HashAlgorithm { }; if let Some(prefix) = DUMP_HASHED_VALUES { - c.map(|c: Box<nettle::Hash>| -> Box<nettle::Hash> { - Box::new(HashDumper::new(c, prefix)) + c.map(|c: Box<nettle::Hash>| { + Context(Box::new(HashDumper::new(c, prefix))) }) } else { - c + c.map(|c| Context(c)) } } @@ -146,12 +184,12 @@ impl nettle::Hash for HashDumper { /// Hashes OpenPGP packets and related types. pub trait Hash { /// Updates the given hash with this object. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H); + fn hash(&self, hash: &mut Context); } impl Hash for UserID { /// Update the Hash with a hash of the user id. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut Context) { let mut header = [0; 5]; header[0] = 0xB4; @@ -168,7 +206,7 @@ impl Hash for UserID { impl Hash for UserAttribute { /// Update the Hash with a hash of the user attribute. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut Context) { let mut header = [0; 5]; header[0] = 0xD1; @@ -185,7 +223,7 @@ impl Hash for UserAttribute { impl Hash for Key4 { /// Update the Hash with a hash of the key. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut Context) { // We hash 8 bytes plus the MPIs. But, the len doesn't // include the tag (1 byte) or the length (2 bytes). let len = (9 - 3) + self.mpis().serialized_len(); @@ -222,7 +260,7 @@ impl Hash for Key4 { impl Hash for Signature { /// Adds the `Signature` to the provided hash context. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut Context) { match self { Signature::V4(sig) => sig.hash(hash), } @@ -231,14 +269,14 @@ impl Hash for Signature { impl Hash for Signature4 { /// Adds the `Signature` to the provided hash context. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut Context) { self.fields.hash(hash); } } impl Hash for signature::Builder { /// Adds the `Signature` to the provided hash context. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut Context) { // A version 4 signature packet is laid out as follows: // // version - 1 byte \ @@ -302,7 +340,7 @@ impl Signature { where S: Into<&'a signature::Builder> { let sig = sig.into(); - let mut h: Box<nettle::Hash> = sig.hash_algo().context()?; + let mut h = sig.hash_algo().context()?; key.hash(&mut h); sig.hash(&mut h); @@ -319,7 +357,7 @@ impl Signature { where S: Into<&'a signature::Builder> { let sig = sig.into(); - let mut h: Box<nettle::Hash> = sig.hash_algo().context()?; + let mut h = sig.hash_algo().context()?; key.hash(&mut h); subkey.hash(&mut h); @@ -337,7 +375,7 @@ impl Signature { where S: Into<&'a signature::Builder> { let sig = sig.into(); - let mut h: Box<nettle::Hash> = sig.hash_algo().context()?; + let mut h = sig.hash_algo().context()?; key.hash(&mut h); userid.hash(&mut h); @@ -356,7 +394,7 @@ impl Signature { where S: Into<&'a signature::Builder> { let sig = sig.into(); - let mut h: Box<nettle::Hash> = sig.hash_algo().context()?; + let mut h = sig.hash_algo().context()?; key.hash(&mut h); ua.hash(&mut h); diff --git a/openpgp/src/crypto/mem.rs b/openpgp/src/crypto/mem.rs index 23b8f146..f6bec6c0 100644 --- a/openpgp/src/crypto/mem.rs +++ b/openpgp/src/crypto/mem.rs @@ -41,6 +41,12 @@ impl AsRef<[u8]> for Protected { } } +impl AsMut<[u8]> for Protected { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + impl DerefMut for Protected { fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 diff --git a/openpgp/src/crypto/mod.rs b/openpgp/src/crypto/mod.rs index 8a37e509..36d6e921 100644 --- a/openpgp/src/crypto/mod.rs +++ b/openpgp/src/crypto/mod.rs @@ -4,7 +4,7 @@ use std::io::Read; use std::ops::{Deref, DerefMut}; use std::fmt; -use nettle::{self, Random, Yarrow}; +use nettle::{Random, Yarrow}; use constants::HashAlgorithm; use Result; @@ -158,7 +158,7 @@ impl fmt::Debug for Password { /// /// This is useful when verifying detached signatures. pub fn hash_file<R: Read>(reader: R, algos: &[HashAlgorithm]) - -> Result<Vec<(HashAlgorithm, Box<nettle::Hash>)>> + -> Result<Vec<(HashAlgorithm, hash::Context)>> { use std::mem; diff --git a/openpgp/src/crypto/mpis.rs b/openpgp/src/crypto/mpis.rs index 117529ea..9c9eecd2 100644 --- a/openpgp/src/crypto/mpis.rs +++ b/openpgp/src/crypto/mpis.rs @@ -1,7 +1,6 @@ //! Multi Precision Integers. use std::fmt; -use std::io::Write; use std::cmp::Ordering; use quickcheck::{Arbitrary, Gen}; @@ -13,7 +12,7 @@ use constants::{ PublicKeyAlgorithm, SymmetricAlgorithm, }; -use crypto::hash::Hash; +use crypto::hash::{self, Hash}; use crypto::mem::{secure_cmp, Protected}; use serialize::Serialize; @@ -187,7 +186,7 @@ impl fmt::Debug for MPI { impl Hash for MPI { /// Update the Hash with a hash of the MPIs. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut hash::Context) { let len = &[(self.bits() >> 8) as u8 & 0xFF, self.bits() as u8]; hash.update(len); @@ -439,7 +438,7 @@ impl PublicKey { impl Hash for PublicKey { /// Update the Hash with a hash of the MPIs. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut hash::Context) { self.serialize(hash).expect("hashing does not fail") } } @@ -726,7 +725,7 @@ impl SecretKey { impl Hash for SecretKey { /// Update the Hash with a hash of the MPIs. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut hash::Context) { self.serialize(hash).expect("hashing does not fail") } } @@ -848,7 +847,7 @@ impl Ciphertext { impl Hash for Ciphertext { /// Update the Hash with a hash of the MPIs. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut hash::Context) { self.serialize(hash).expect("hashing does not fail") } } @@ -960,7 +959,7 @@ impl Signature { impl Hash for Signature { /// Update the Hash with a hash of the MPIs. - fn hash<H: nettle::Hash + Write>(&self, hash: &mut H) { + fn hash(&self, hash: &mut hash::Context) { self.serialize(hash).expect("hashing does not fail") } } diff --git a/openpgp/src/crypto/s2k.rs b/openpgp/src/crypto/s2k.rs index 4fc87096..b3e099e2 100644 --- a/openpgp/src/crypto/s2k.rs +++ b/openpgp/src/crypto/s2k.rs @@ -14,7 +14,7 @@ use crypto::SessionKey; use std::fmt; -use nettle::{Hash, Yarrow, Random}; +use nettle::{Yarrow, Random}; use quickcheck::{Arbitrary, Gen}; use rand::Rng; |