summaryrefslogtreecommitdiffstats
path: root/openpgp/src/parse/hashed_reader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/parse/hashed_reader.rs')
-rw-r--r--openpgp/src/parse/hashed_reader.rs147
1 files changed, 91 insertions, 56 deletions
diff --git a/openpgp/src/parse/hashed_reader.rs b/openpgp/src/parse/hashed_reader.rs
index 51549060..1335c7c0 100644
--- a/openpgp/src/parse/hashed_reader.rs
+++ b/openpgp/src/parse/hashed_reader.rs
@@ -7,6 +7,8 @@ use buffered_reader::BufferedReader;
use buffered_reader::buffered_reader_generic_read_impl;
use crate::crypto::hash::Digest;
+use crate::fmt::hex;
+use crate::packet::Signature;
use crate::parse::{Cookie, HashesFor, Hashing};
use crate::Result;
use crate::types::HashAlgorithm;
@@ -23,25 +25,34 @@ pub(crate) enum HashingMode<T> {
/// Hash for a binary signature.
///
/// The data is hashed as-is.
- Binary(T),
+ Binary(Vec<u8>, T),
/// Hash for a text signature.
///
/// The data is hashed with line endings normalized to `\r\n`.
- Text(T),
+ Text(Vec<u8>, T),
/// Like Text, but the last character that we hashed was a '\r'
/// that we converted to a '\r\n'.
- TextLastWasCr(T),
+ TextLastWasCr(Vec<u8>, T),
}
impl<T: std::fmt::Debug> std::fmt::Debug for HashingMode<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use self::HashingMode::*;
match self {
- Binary(t) => write!(f, "Binary({:?})", t),
- Text(t) => write!(f, "Text({:?})", t),
- TextLastWasCr(t) => write!(f, "Text(last was CR, {:?})", t),
+ Binary(salt, t) if salt.is_empty() =>
+ write!(f, "Binary({:?})", t),
+ Binary(salt, t) =>
+ write!(f, "Binary({}, {:?})", hex::encode(salt), t),
+ Text(salt, t) if salt.is_empty() =>
+ write!(f, "Text({:?})", t),
+ Text(salt, t) =>
+ write!(f, "Text({}, {:?})", hex::encode(salt), t),
+ TextLastWasCr(salt, t) if salt.is_empty() =>
+ write!(f, "Text(last was CR, {:?})", t),
+ TextLastWasCr(salt, t) =>
+ write!(f, "Text(last was CR, {}, {:?})", hex::encode(salt), t),
}
}
}
@@ -50,12 +61,17 @@ impl<T: PartialEq> PartialEq for HashingMode<T> {
fn eq(&self, other: &Self) -> bool {
use self::HashingMode::*;
match (self, other) {
- (Binary(s), Binary(o)) => s.eq(o),
-
- (Text(s), Text(o)) => s.eq(o),
- (TextLastWasCr(s), Text(o)) => s.eq(o),
- (Text(s), TextLastWasCr(o)) => s.eq(o),
- (TextLastWasCr(s), TextLastWasCr(o)) => s.eq(o),
+ (Binary(salt_s, s), Binary(salt_o, o)) =>
+ salt_s == salt_o && s == o,
+
+ (Text(salt_s, s), Text(salt_o, o)) =>
+ salt_s == salt_o && s == o,
+ (TextLastWasCr(salt_s, s), Text(salt_o, o)) =>
+ salt_s == salt_o && s == o,
+ (Text(salt_s, s), TextLastWasCr(salt_o, o)) =>
+ salt_s == salt_o && s == o,
+ (TextLastWasCr(salt_s, s), TextLastWasCr(salt_o, o)) =>
+ salt_s == salt_o && s == o,
_ => false,
}
@@ -66,9 +82,9 @@ impl<T> HashingMode<T> {
pub(crate) fn map<U, F: Fn(&T) -> U>(&self, f: F) -> HashingMode<U> {
use self::HashingMode::*;
match self {
- Binary(t) => Binary(f(t)),
- Text(t) => Text(f(t)),
- TextLastWasCr(t) => TextLastWasCr(f(t)),
+ Binary(salt, t) => Binary(salt.clone(), f(t)),
+ Text(salt, t) => Text(salt.clone(), f(t)),
+ TextLastWasCr(salt, t) => TextLastWasCr(salt.clone(), f(t)),
}
}
@@ -76,44 +92,62 @@ impl<T> HashingMode<T> {
-> Result<HashingMode<U>> {
use self::HashingMode::*;
match self {
- Binary(t) => Ok(Binary(f(t)?)),
- Text(t) => Ok(Text(f(t)?)),
- TextLastWasCr(t) => Ok(TextLastWasCr(f(t)?)),
+ Binary(salt, t) => Ok(Binary(salt.clone(), f(t)?)),
+ Text(salt, t) => Ok(Text(salt.clone(), f(t)?)),
+ TextLastWasCr(salt, t) => Ok(TextLastWasCr(salt.clone(), f(t)?)),
+ }
+ }
+
+ pub(crate) fn salt(&self) -> &[u8] {
+ use self::HashingMode::*;
+ match self {
+ Binary(salt, _t) => salt,
+ Text(salt, _t) => salt,
+ TextLastWasCr(salt, _t) => salt,
}
}
pub(crate) fn as_ref(&self) -> &T {
use self::HashingMode::*;
match self {
- Binary(t) => t,
- Text(t) => t,
- TextLastWasCr(t) => t,
+ Binary(_salt, t) => t,
+ Text(_salt, t) => t,
+ TextLastWasCr(_salt, t) => t,
}
}
pub(crate) fn as_mut(&mut self) -> &mut T {
use self::HashingMode::*;
match self {
- Binary(t) => t,
- Text(t) => t,
- TextLastWasCr(t) => t,
+ Binary(_salt, t) => t,
+ Text(_salt, t) => t,
+ TextLastWasCr(_salt, t) => t,
}
}
- pub(crate) fn for_signature(t: T, typ: SignatureType) -> Self {
+ pub(crate) fn for_signature(t: T, s: &Signature) -> Self {
+ match s {
+ Signature::V3(s) => Self::for_salt_and_type(t, &[], s.typ()),
+ Signature::V4(s) => Self::for_salt_and_type(t, &[], s.typ()),
+ Signature::V6(s) => Self::for_salt_and_type(t, s.salt(), s.typ()),
+ }
+ }
+ pub(crate) fn for_salt_and_type(t: T, salt: &[u8], typ: SignatureType)
+ -> Self
+ {
if typ == SignatureType::Text {
- HashingMode::Text(t)
+ HashingMode::Text(salt.into(), t)
} else {
- HashingMode::Binary(t)
+ HashingMode::Binary(salt.into(), t)
}
}
pub(crate) fn into_inner(self) -> T {
use self::HashingMode::*;
match self {
- Binary(t) => t,
- Text(t) => t,
- TextLastWasCr(t) => t,
+ Binary(_salt, t) => t,
+ Text(_salt, t) => t,
+ TextLastWasCr(_salt, t) => t,
}
}
}
@@ -132,9 +166,9 @@ impl<D> HashingMode<D>
}
let (h, mut last_was_cr) = match self {
- HashingMode::Text(h) => (h, false),
- HashingMode::TextLastWasCr(h) => (h, true),
- HashingMode::Binary(h) => return h.update(data),
+ HashingMode::Text(_salt, h) => (h, false),
+ HashingMode::TextLastWasCr(_salt, h) => (h, true),
+ HashingMode::Binary(_salt, h) => return h.update(data),
};
let mut line = data;
@@ -173,19 +207,21 @@ impl<D> HashingMode<D>
}
match (&mut *self, last_is_cr) {
- (&mut HashingMode::Text(_), false) => {
+ (&mut HashingMode::Text(_, _), false) => {
// This is the common case. Getting a crlf that is
// split across two chunks is extremely rare. Hence,
// the clones used to change the variant are rarely
// needed.
},
- (&mut HashingMode::Text(ref mut h), true) => {
- *self = HashingMode::TextLastWasCr(h.clone());
+ (&mut HashingMode::Text(ref mut salt, ref mut h), true) => {
+ *self =
+ HashingMode::TextLastWasCr(std::mem::take(salt), h.clone());
}
- (&mut HashingMode::TextLastWasCr(ref mut h), false) => {
- *self = HashingMode::Text(h.clone());
+ (&mut HashingMode::TextLastWasCr(ref mut salt, ref mut h), false) =>
+ {
+ *self = HashingMode::Text(std::mem::take(salt), h.clone());
},
- (&mut HashingMode::TextLastWasCr(_), true) => (),
+ (&mut HashingMode::TextLastWasCr(_, _), true) => (),
_ => unreachable!("handled above"),
}
@@ -217,19 +253,19 @@ impl<R: BufferedReader<Cookie>> HashedReader<R> {
/// purpose. `algos` is a list of algorithms for which we should
/// compute the hash.
pub fn new(reader: R, hashes_for: HashesFor,
- salt: Vec<u8>,
algos: Vec<HashingMode<HashAlgorithm>>)
-> Result<Self> {
let mut cookie = Cookie::default();
for mode in algos {
+ let salt = mode.salt().to_vec();
let mode = mode.mapf(|algo| {
let mut ctx = algo.context()?;
ctx.update(&salt);
Ok(ctx)
})?;
- cookie.sig_group_mut().hashes.push((salt.clone(), mode));
+ cookie.sig_group_mut().hashes.push(mode);
}
cookie.hashes_for = hashes_for;
@@ -267,13 +303,12 @@ impl Cookie {
assert!(ngroups > 1);
for h in self.sig_groups[ngroups-2].hashes.iter_mut()
{
- t!("({:?}): group {} {:?} (salted: {:?} hashing {} stashed bytes)",
+ t!("({:?}): group {} {:?} hashing {} stashed bytes.",
hashes_for, ngroups-2,
- h.1.map(|ctx| ctx.algo()),
- ! h.0.is_empty(),
+ h.map(|ctx| ctx.algo()),
data.len());
- h.1.update(&stashed_data);
+ h.update(&stashed_data);
}
}
@@ -298,8 +333,8 @@ impl Cookie {
for h in sig_group.hashes.iter_mut() {
t!("{:?}: group {} {:?} hashing {} bytes.",
- hashes_for, i, h.1.map(|ctx| ctx.algo()), data.len());
- h.1.update(data);
+ hashes_for, i, h.map(|ctx| ctx.algo()), data.len());
+ h.update(data);
}
}
}
@@ -333,8 +368,8 @@ impl Cookie {
// Hash the data.
for h in self.sig_groups[0].hashes.iter_mut() {
t!("{:?}: {:?} hashing {} bytes.",
- hashes_for, h.1.map(|ctx| ctx.algo()), data.len());
- h.1.update(data);
+ hashes_for, h.map(|ctx| ctx.algo()), data.len());
+ h.update(data);
}
}
}
@@ -463,14 +498,14 @@ pub(crate) fn hash_buffered_reader<R>(reader: R,
where R: BufferedReader<crate::parse::Cookie>,
{
let mut reader
- = HashedReader::new(reader, HashesFor::Signature, vec![], algos.to_vec())?;
+ = HashedReader::new(reader, HashesFor::Signature, algos.to_vec())?;
// Hash all of the data.
reader.drop_eof()?;
let hashes =
mem::take(&mut reader.cookie_mut().sig_group_mut().hashes);
- Ok(hashes.into_iter().map(|h| h.1).collect())
+ Ok(hashes)
}
#[cfg(test)]
@@ -518,9 +553,8 @@ mod test {
test.data, None, Default::default());
let mut reader
= HashedReader::new(reader, HashesFor::MDC,
- vec![],
test.expected.keys().cloned()
- .map(HashingMode::Binary)
+ .map(|v| HashingMode::Binary(vec![], v))
.collect()).unwrap();
assert_eq!(reader.steal_eof().unwrap(), test.data);
@@ -528,7 +562,7 @@ mod test {
let cookie = reader.cookie_mut();
let mut hashes = std::mem::take(&mut cookie.sig_group_mut().hashes);
- for (_salt, mode) in hashes.iter_mut() {
+ for mode in hashes.iter_mut() {
let hash = mode.as_mut();
let algo = hash.algo();
let mut digest = vec![0u8; hash.digest_size()];
@@ -553,7 +587,8 @@ mod test {
] {
for chunk_size in &[ text.len(), 1 ] {
let mut ctx
- = HashingMode::Text(HashAlgorithm::SHA256.context()?);
+ = HashingMode::Text(vec![],
+ HashAlgorithm::SHA256.context()?);
for chunk in text.as_bytes().chunks(*chunk_size) {
ctx.update(chunk);
}
@@ -589,7 +624,7 @@ mod test {
hash_buffered_reader(
reader,
&expected.keys().cloned()
- .map(HashingMode::Binary).
+ .map(|v| HashingMode::Binary(vec![], v)).
collect::<Vec<_>>())
.unwrap();