diff --git a/Cargo.lock b/Cargo.lock index 1808d27..1e7ab39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" version = "0.7.18" @@ -123,21 +108,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "backtrace" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f" -dependencies = [ - "addr2line", - "cc", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "base-x" version = "0.2.8" @@ -873,12 +843,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46dd079379f756f6a1ae74b051813e242893f84fbf6ac898bce827fc77958d70" -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - [[package]] name = "glob" version = "0.3.0" @@ -957,7 +921,7 @@ dependencies = [ "fs2", "hex", "idna 0.1.5", - "log 0.4.16", + "log 0.3.9", "multipart", "pathdiff", "rand 0.6.5", @@ -984,7 +948,7 @@ dependencies = [ "hex", "idna 0.1.5", "indicatif", - "log 0.4.16", + "log 0.3.9", "multipart", "pathdiff", "rand 0.6.5", @@ -1126,7 +1090,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5617e92fc2f2501c3e2bc6ce547cad841adba2bae5b921c7e52510beca6d084c" dependencies = [ - "base64 0.13.0", + "base64 0.10.1", "bytes", "http", "httpdate", @@ -1178,7 +1142,7 @@ dependencies = [ "console", "lazy_static", "number_prefix", - "parking_lot 0.12.0", + "parking_lot 0.11.2", "regex", ] @@ -1290,7 +1254,6 @@ dependencies = [ "itertools", "lalrpop-util", "petgraph", - "pico-args", "regex", "regex-syntax", "string_cache", @@ -1304,9 +1267,6 @@ name = "lalrpop-util" version = "0.19.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6d265705249fe209280676d8f68887859fa42e1d34f342fc05bd47726a5e188" -dependencies = [ - "regex", -] [[package]] name = "language-tags" @@ -1479,16 +1439,6 @@ dependencies = [ "unicase 2.6.0", ] -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg 1.1.0", -] - [[package]] name = "mio" version = "0.6.23" @@ -1761,15 +1711,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "object" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.10.0" @@ -1978,12 +1919,6 @@ dependencies = [ "siphasher 0.3.10", ] -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - [[package]] name = "pin-project-lite" version = "0.2.8" @@ -2500,12 +2435,6 @@ dependencies = [ "rocket", ] -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - [[package]] name = "rustc-hash" version = "1.1.0" @@ -2592,12 +2521,11 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "sequoia-openpgp" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb4b27d94976e5cd885a6f2b76cf881aeaca69d93a15bc71e8f4e27917e850c" +checksum = "50d9033c24b1d41fdfab2bbde66005d324625b4abee2af2aea6135bdd9543ff7" dependencies = [ "anyhow", - "backtrace", "base64 0.13.0", "buffered-reader", "chrono", @@ -2683,7 +2611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31bf4e9fe5cd8cea8e0887e2e4eb1b4d736ff11b776c8537bf0912a4b381285" dependencies = [ "digest 0.9.0", - "generic-array 0.14.5", + "generic-array 0.12.4", ] [[package]] diff --git a/rust-toolchain b/rust-toolchain index 69478d1..4d5fde5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.58.1 +1.60.0 diff --git a/src/dump.rs b/src/dump.rs index 2fc4078..a640533 100644 --- a/src/dump.rs +++ b/src/dump.rs @@ -1,7 +1,7 @@ use std::io::{self, Read}; use self::openpgp::crypto::mpi; -use self::openpgp::crypto::{SessionKey, S2K}; +use self::openpgp::crypto::S2K; use self::openpgp::fmt::hex; use self::openpgp::packet::header::CTB; use self::openpgp::packet::prelude::*; @@ -12,6 +12,38 @@ use self::openpgp::types::{Duration, SymmetricAlgorithm, Timestamp}; use self::openpgp::{Packet, Result}; use sequoia_openpgp as openpgp; +pub struct SessionKey { + pub session_key: openpgp::crypto::SessionKey, + pub symmetric_algo: Option, +} + +impl SessionKey { + /// Returns an object that implements Display for explicitly opting into + /// printing a `SessionKey`. + pub fn display_sensitive(&self) -> SessionKeyDisplay { + SessionKeyDisplay { csk: self } + } +} + +/// Helper struct for intentionally printing session keys with format! and {}. +/// +/// This struct implements the `Display` trait to print the session key. This +/// construct requires the user to explicitly call +/// [`SessionKey::display_sensitive`]. By requiring the user to opt-in, this +/// will hopefully reduce that the chance that the session key is inadvertently +/// leaked, e.g., in a log that may be publicly posted. +pub struct SessionKeyDisplay<'a> { + csk: &'a SessionKey, +} + +/// Print the session key without prefix in hexadecimal representation. +impl<'a> std::fmt::Display for SessionKeyDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let sk = self.csk; + write!(f, "{}", hex::encode(&sk.session_key)) + } +} + #[derive(Debug)] pub enum Kind { Message { encrypted: bool }, @@ -86,29 +118,28 @@ where } Packet::SEIP(_) if sk.is_some() => { message_encrypted = true; - let sk = sk.as_ref().unwrap(); - let mut decrypted_with = None; - for algo in 1..20 { - let algo = SymmetricAlgorithm::from(algo); - if let Ok(size) = algo.key_size() { - if size != sk.len() { - continue; - } - } else { - continue; - } + let sk = sk.unwrap(); + let decrypted_with = if let Some(algo) = sk.symmetric_algo { + // We know which algorithm to use, so only try decrypting + // with that one. + pp.decrypt(algo, &sk.session_key).is_ok().then(|| algo) + } else { + // We don't know which algorithm to use, + // try to find one that decrypts the message. + (1u8..=19) + .map(SymmetricAlgorithm::from) + .find(|algo| pp.decrypt(*algo, &sk.session_key).is_ok()) + }; - if let Ok(_) = pp.decrypt(algo, sk) { - decrypted_with = Some(algo); - break; - } - } let mut fields = Vec::new(); - fields.push(format!("Session key: {}", hex::encode(sk))); + fields.push(format!("Session key: {}", &sk.display_sensitive())); if let Some(algo) = decrypted_with { fields.push(format!("Symmetric algo: {}", algo)); fields.push("Decryption successful".into()); } else { + if let Some(algo) = sk.symmetric_algo { + fields.push(format!("Indicated Symmetric algo: {}", algo)); + }; fields.push("Decryption failed".into()); } Some(fields) @@ -126,14 +157,14 @@ where unreachable!() }; - let _ = pp.decrypt(algo, sk); + let _ = pp.decrypt(algo, &sk.session_key); let mut fields = Vec::new(); - fields.push(format!("Session key: {}", hex::encode(sk))); - if pp.encrypted() { - fields.push("Decryption failed".into()); - } else { + fields.push(format!("Session key: {}", sk.display_sensitive())); + if pp.processed() { fields.push("Decryption successful".into()); + } else { + fields.push("Decryption failed".into()); } Some(fields) } @@ -403,8 +434,8 @@ impl PacketDumper { sym, } => { writeln!(output, "{} Curve: {}", ii, curve)?; - writeln!(output, "{} Hash algo: {}", ii, hash)?; - writeln!(output, "{} Symmetric algo: {}", ii, sym)?; + writeln!(output, "{} KDF hash algo: {}", ii, hash)?; + writeln!(output, "{} KEK symmetric algo: {}", ii, sym)?; pd.dump_mpis(output, &ii, &[q.value()], &["q"])?; } mpi::PublicKey::Unknown { mpis, rest } => { @@ -465,17 +496,11 @@ impl PacketDumper { let keys: Vec = (0..mpis.len()).map(|i| format!("mpi{}", i)).collect(); pd.dump_mpis( - output, - &ii, - &mpis - .iter() - .map(|m| { - m.value().iter().as_slice() - }) - .collect::>()[..], - &keys - .iter() - .map(|k| k.as_str()) + output, &ii, + &mpis.iter().map(|m| { + m.value().iter().as_slice() + }).collect::>()[..], + &keys.iter().map(|k| k.as_str()) .collect::>()[..], )?; @@ -787,8 +812,9 @@ impl PacketDumper { } } + writeln!(output, "{}", i)?; + if let Some(map) = map { - writeln!(output, "{}", i)?; let mut hd = hex::Dumper::new( output, self.indentation_for_hexdump( @@ -816,8 +842,6 @@ impl PacketDumper { let output = hd.into_inner(); writeln!(output, "{}", i)?; - } else { - writeln!(output, "{}", i)?; } Ok(()) @@ -864,9 +888,7 @@ impl PacketDumper { i, t.convert(), if let Some(creation) = sig.signature_creation_time() { - (creation + std::time::Duration::from(*t)) - .convert() - .to_string() + (creation + std::time::Duration::from(*t)).convert().to_string() } else { " (no Signature Creation Time subpacket)".into() }