summaryrefslogtreecommitdiffstats
path: root/openpgp/src/crypto
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-07-02 16:11:25 +0200
committerJustus Winter <justus@sequoia-pgp.org>2019-07-02 16:11:25 +0200
commit9761b660b508d9440b192616f70c1a2d45cbbcb9 (patch)
treee2539088fc683564fad4ca1f29a94f00387477fe /openpgp/src/crypto
parenta5548dc2e4db5b4a5469e7b320f37f89e32bb1b3 (diff)
openpgp: Introduce an abstraction for hash contexts.
- See #302.
Diffstat (limited to 'openpgp/src/crypto')
-rw-r--r--openpgp/src/crypto/hash.rs70
-rw-r--r--openpgp/src/crypto/mem.rs6
-rw-r--r--openpgp/src/crypto/mod.rs4
-rw-r--r--openpgp/src/crypto/mpis.rs13
-rw-r--r--openpgp/src/crypto/s2k.rs2
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;