diff --git a/src/contact.rs b/src/contact.rs index 0fff01025..67002a658 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -12,7 +12,7 @@ use crate::context::Context; use crate::dc_tools::*; use crate::error::{bail, ensure, format_err, Result}; use crate::events::Event; -use crate::key::{DcKey, Key, SignedPublicKey}; +use crate::key::{DcKey, SignedPublicKey}; use crate::login_param::LoginParam; use crate::message::{MessageState, MsgId}; use crate::mimeparser::AvatarAction; @@ -691,18 +691,20 @@ impl Contact { }) .await; ret += &p; - let self_key = Key::from(SignedPublicKey::load_self(context).await?); let p = context.stock_str(StockMessage::FingerPrints).await; ret += &format!(" {}:", p); - let fingerprint_self = self_key.formatted_fingerprint(); + let fingerprint_self = SignedPublicKey::load_self(context) + .await? + .fingerprint() + .to_string(); let fingerprint_other_verified = peerstate .peek_key(PeerstateVerifiedStatus::BidirectVerified) - .map(|k| k.formatted_fingerprint()) + .map(|k| k.fingerprint().to_string()) .unwrap_or_default(); let fingerprint_other_unverified = peerstate .peek_key(PeerstateVerifiedStatus::Unverified) - .map(|k| k.formatted_fingerprint()) + .map(|k| k.fingerprint().to_string()) .unwrap_or_default(); if loginparam.addr < peerstate.addr { cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, ""); diff --git a/src/context.rs b/src/context.rs index cb6370b51..de431703f 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,7 +15,7 @@ use crate::dc_tools::duration_to_str; use crate::error::*; use crate::events::{Event, EventEmitter, Events}; use crate::job::{self, Action}; -use crate::key::{DcKey, Key, SignedPublicKey}; +use crate::key::{DcKey, SignedPublicKey}; use crate::login_param::LoginParam; use crate::lot::Lot; use crate::message::{self, Message, MessengerMessage, MsgId}; @@ -285,7 +285,7 @@ impl Context { .query_get_value(self, "SELECT COUNT(*) FROM acpeerstates;", paramsv![]) .await; let fingerprint_str = match SignedPublicKey::load_self(self).await { - Ok(key) => Key::from(key).fingerprint(), + Ok(key) => key.fingerprint().hex(), Err(err) => format!("", err), }; diff --git a/src/e2ee.rs b/src/e2ee.rs index bb3f985d3..bd20279cc 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -93,7 +93,7 @@ impl EncryptHelper { mail_to_encrypt: lettre_email::PartBuilder, peerstates: Vec<(Option>, &str)>, ) -> Result { - let mut keyring = Keyring::default(); + let mut keyring: Keyring = Keyring::new(); for (peerstate, addr) in peerstates .into_iter() @@ -104,8 +104,7 @@ impl EncryptHelper { })?; keyring.add(key); } - let public_key = Key::from(self.public_key); - keyring.add(public_key); + keyring.add(self.public_key.clone()); let sign_key = Key::from(SignedSecretKey::load_self(context).await?); let raw_message = mail_to_encrypt.build().as_string().into_bytes(); @@ -151,40 +150,33 @@ pub async fn try_decrypt( } /* possibly perform decryption */ - let mut public_keyring_for_validate = Keyring::default(); - let mut out_mail = None; + let private_keyring: Keyring = Keyring::new_self(context).await?; + let mut public_keyring_for_validate: Keyring = Keyring::new(); let mut signatures = HashSet::default(); - let self_addr = context.get_config(Config::ConfiguredAddr).await; - if let Some(self_addr) = self_addr { - if let Ok(private_keyring) = - Keyring::load_self_private_for_decrypting(context, self_addr).await - { - if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 { - peerstate = Peerstate::from_addr(&context, &from).await; - } - if let Some(peerstate) = peerstate { - if peerstate.degrade_event.is_some() { - handle_degrade_event(context, &peerstate).await?; - } - if let Some(key) = peerstate.gossip_key { - public_keyring_for_validate.add(key); - } - if let Some(key) = peerstate.public_key { - public_keyring_for_validate.add(key); - } - } - - out_mail = decrypt_if_autocrypt_message( - context, - mail, - private_keyring, - public_keyring_for_validate, - &mut signatures, - ) - .await?; + if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 { + peerstate = Peerstate::from_addr(&context, &from).await; + } + if let Some(peerstate) = peerstate { + if peerstate.degrade_event.is_some() { + handle_degrade_event(context, &peerstate).await?; + } + if let Some(key) = peerstate.gossip_key { + public_keyring_for_validate.add(key); + } + if let Some(key) = peerstate.public_key { + public_keyring_for_validate.add(key); } } + + let out_mail = decrypt_if_autocrypt_message( + context, + mail, + private_keyring, + public_keyring_for_validate, + &mut signatures, + ) + .await?; Ok((out_mail, signatures)) } @@ -218,8 +210,8 @@ fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail async fn decrypt_if_autocrypt_message<'a>( context: &Context, mail: &ParsedMail<'a>, - private_keyring: Keyring, - public_keyring_for_validate: Keyring, + private_keyring: Keyring, + public_keyring_for_validate: Keyring, ret_valid_signatures: &mut HashSet, ) -> Result>> { // The returned bool is true if we detected an Autocrypt-encrypted @@ -250,8 +242,8 @@ async fn decrypt_if_autocrypt_message<'a>( /// Returns Ok(None) if nothing encrypted was found. async fn decrypt_part( mail: &ParsedMail<'_>, - private_keyring: Keyring, - public_keyring_for_validate: Keyring, + private_keyring: Keyring, + public_keyring_for_validate: Keyring, ret_valid_signatures: &mut HashSet, ) -> Result>> { let data = mail.get_body_raw()?; diff --git a/src/key.rs b/src/key.rs index 035507b5e..4816e3297 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,6 +1,7 @@ //! Cryptographic key module use std::collections::BTreeMap; +use std::fmt; use std::io::Cursor; use async_std::path::Path; @@ -50,8 +51,8 @@ pub type Result = std::result::Result; /// [SignedSecretKey] types and makes working with them a little /// easier in the deltachat world. #[async_trait] -pub trait DcKey: Serialize + Deserializable { - type KeyType: Serialize + Deserializable; +pub trait DcKey: Serialize + Deserializable + KeyTrait + Clone { + type KeyType: Serialize + Deserializable + KeyTrait + Clone; /// Create a key from some bytes. fn from_slice(bytes: &[u8]) -> Result { @@ -71,15 +72,25 @@ pub trait DcKey: Serialize + Deserializable { /// Load the users' default key from the database. async fn load_self(context: &Context) -> Result; - /// Serialise the key to a base64 string. - fn to_base64(&self) -> String { + /// Serialise the key as bytes. + fn to_bytes(&self) -> Vec { // Not using Serialize::to_bytes() to make clear *why* it is // safe to ignore this error. // Because we write to a Vec the io::Write impls never // fail and we can hide this error. let mut buf = Vec::new(); self.to_writer(&mut buf).unwrap(); - base64::encode(&buf) + buf + } + + /// Serialise the key to a base64 string. + fn to_base64(&self) -> String { + base64::encode(&DcKey::to_bytes(self)) + } + + /// The fingerprint for the key. + fn fingerprint(&self) -> Fingerprint { + Fingerprint::new(KeyTrait::fingerprint(self)) } } @@ -300,8 +311,8 @@ impl Key { pub fn to_bytes(&self) -> Vec { match self { - Key::Public(k) => k.to_bytes().unwrap_or_default(), - Key::Secret(k) => k.to_bytes().unwrap_or_default(), + Key::Public(k) => Serialize::to_bytes(&k).unwrap_or_default(), + Key::Secret(k) => Serialize::to_bytes(&k).unwrap_or_default(), } } @@ -312,11 +323,6 @@ impl Key { } } - pub fn to_base64(&self) -> String { - let buf = self.to_bytes(); - base64::encode(&buf) - } - pub fn to_armored_string( &self, headers: Option<&BTreeMap>, @@ -353,18 +359,6 @@ impl Key { res } - pub fn fingerprint(&self) -> String { - match self { - Key::Public(k) => hex::encode_upper(k.fingerprint()), - Key::Secret(k) => hex::encode_upper(k.fingerprint()), - } - } - - pub fn formatted_fingerprint(&self) -> String { - let rawhex = self.fingerprint(); - dc_format_fingerprint(&rawhex) - } - pub fn split_key(&self) -> Option { match self { Key::Public(_) => None, @@ -425,14 +419,8 @@ pub async fn store_self_keypair( ) -> std::result::Result<(), SaveKeyError> { // Everything should really be one transaction, more refactoring // is needed for that. - let public_key = keypair - .public - .to_bytes() - .map_err(|err| SaveKeyError::new("failed to serialise public key", err))?; - let secret_key = keypair - .secret - .to_bytes() - .map_err(|err| SaveKeyError::new("failed to serialise secret key", err))?; + let public_key = DcKey::to_bytes(&keypair.public); + let secret_key = DcKey::to_bytes(&keypair.secret); context .sql .execute( @@ -470,6 +458,62 @@ pub async fn store_self_keypair( Ok(()) } +/// A key fingerprint +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Fingerprint(Vec); + +impl Fingerprint { + pub fn new(v: Vec) -> Fingerprint { + Fingerprint(v) + } + + /// Make a hex string from the fingerprint. + /// + /// Use [std::fmt::Display] or [ToString::to_string] to get a + /// human-readable formatted string. + pub fn hex(&self) -> String { + hex::encode_upper(&self.0) + } +} + +/// Make a human-readable fingerprint. +impl fmt::Display for Fingerprint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Split key into chunks of 4 with space and newline at 20 chars + for (i, c) in self.hex().chars().enumerate() { + if i > 0 && i % 20 == 0 { + writeln!(f)?; + } else if i > 0 && i % 4 == 0 { + write!(f, " ")?; + } + write!(f, "{}", c)?; + } + Ok(()) + } +} + +/// Parse a human-readable or otherwise formatted fingerprint. +impl std::str::FromStr for Fingerprint { + type Err = hex::FromHexError; + + fn from_str(input: &str) -> std::result::Result { + let hex_repr: String = input + .chars() + .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') + .collect(); + let v: Vec = hex::decode(hex_repr)?; + Ok(Fingerprint(v)) + } +} + +/// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format. +pub fn dc_normalize_fingerprint(fp: &str) -> String { + fp.to_uppercase() + .chars() + .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') + .collect() +} + /// Make a fingerprint human-readable, in hex format. pub fn dc_format_fingerprint(fingerprint: &str) -> String { // split key into chunks of 4 with space, and 20 newline @@ -488,14 +532,6 @@ pub fn dc_format_fingerprint(fingerprint: &str) -> String { res } -/// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format. -pub fn dc_normalize_fingerprint(fp: &str) -> String { - fp.to_uppercase() - .chars() - .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') - .collect() -} - #[cfg(test)] mod tests { use super::*; @@ -755,4 +791,35 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD // ) // .unwrap(); // } + + #[test] + fn test_fingerprint_from_str() { + let res = Fingerprint::new(vec![1, 2, 4, 8, 16, 32, 64, 128, 255]); + + let fp: Fingerprint = "0102040810204080FF".parse().unwrap(); + assert_eq!(fp, res); + + let fp: Fingerprint = "zzzz 0102 0408\n1020 4080 FF zzz".parse().unwrap(); + assert_eq!(fp, res); + + let err = "1".parse::().err().unwrap(); + assert_eq!(err, hex::FromHexError::OddLength); + } + + #[test] + fn test_fingerprint_hex() { + let fp = Fingerprint::new(vec![1, 2, 4, 8, 16, 32, 64, 128, 255]); + assert_eq!(fp.hex(), "0102040810204080FF"); + } + + #[test] + fn test_fingerprint_to_string() { + let fp = Fingerprint::new(vec![ + 1, 2, 4, 8, 16, 32, 64, 128, 255, 1, 2, 4, 8, 16, 32, 64, 128, 255, + ]); + assert_eq!( + fp.to_string(), + "0102 0408 1020 4080 FF01\n0204 0810 2040 80FF" + ); + } } diff --git a/src/keyring.rs b/src/keyring.rs index c962e3fbd..4239e47a1 100644 --- a/src/keyring.rs +++ b/src/keyring.rs @@ -1,17 +1,47 @@ +//! Keyring to perform rpgp operations with. + use anyhow::Result; -use crate::constants::KeyType; use crate::context::Context; -use crate::key::Key; +use crate::key::{self, DcKey}; -#[derive(Default, Clone, Debug)] -pub struct Keyring { - keys: Vec, +/// An in-memory keyring. +/// +/// Instances are usually constructed just for the rpgp operation and +/// short-lived. +#[derive(Clone, Debug, Default)] +pub struct Keyring +where + T: DcKey, +{ + keys: Vec, } -impl Keyring { - pub fn add(&mut self, key: Key) { - self.keys.push(key) +impl Keyring +where + T: DcKey, +{ + /// New empty keyring. + pub fn new() -> Keyring { + Keyring { keys: Vec::new() } + } + + /// Create a new keyring with the the user's secret key loaded. + pub async fn new_self(context: &Context) -> Result, key::Error> { + let mut keyring: Keyring = Keyring::new(); + keyring.load_self(context).await?; + Ok(keyring) + } + + /// Load the user's key into the keyring. + pub async fn load_self(&mut self, context: &Context) -> Result<(), key::Error> { + self.add(T::load_self(context).await?); + Ok(()) + } + + /// Add a key to the keyring. + pub fn add(&mut self, key: T) { + self.keys.push(key); } pub fn len(&self) -> usize { @@ -22,26 +52,41 @@ impl Keyring { self.keys.is_empty() } - pub fn keys(&self) -> &[Key] { + /// A vector with reference to all the keys in the keyring. + pub fn keys(&self) -> &[T] { &self.keys } +} - pub async fn load_self_private_for_decrypting( - context: &Context, - self_addr: impl AsRef, - ) -> Result { - let blob: Vec = context - .sql - .query_get_value_result( - "SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;", - paramsv![self_addr.as_ref().to_string()], - ) - .await? - .unwrap_or_default(); +#[cfg(test)] +mod tests { + use super::*; + use crate::key::{SignedPublicKey, SignedSecretKey}; + use crate::test_utils::*; - let key = async_std::task::spawn_blocking(move || Key::from_slice(&blob, KeyType::Private)) - .await?; + #[test] + fn test_keyring_add_keys() { + let alice = alice_keypair(); + let mut pub_ring: Keyring = Keyring::new(); + pub_ring.add(alice.public.clone()); + assert_eq!(pub_ring.keys(), [alice.public]); - Ok(Self { keys: vec![key] }) + let mut sec_ring: Keyring = Keyring::new(); + sec_ring.add(alice.secret.clone()); + assert_eq!(sec_ring.keys(), [alice.secret]); + } + + #[async_std::test] + async fn test_keyring_load_self() { + // new_self() implies load_self() + let t = dummy_context().await; + configure_alice_keypair(&t.ctx).await; + let alice = alice_keypair(); + + let pub_ring: Keyring = Keyring::new_self(&t.ctx).await.unwrap(); + assert_eq!(pub_ring.keys(), [alice.public]); + + let sec_ring: Keyring = Keyring::new_self(&t.ctx).await.unwrap(); + assert_eq!(sec_ring.keys(), [alice.secret]); } } diff --git a/src/peerstate.rs b/src/peerstate.rs index fc36020a6..f6c460e6a 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -6,9 +6,8 @@ use std::fmt; use num_traits::FromPrimitive; use crate::aheader::*; -use crate::constants::*; use crate::context::Context; -use crate::key::{Key, SignedPublicKey}; +use crate::key::{DcKey, SignedPublicKey}; use crate::sql::Sql; #[derive(Debug)] @@ -32,12 +31,12 @@ pub struct Peerstate<'a> { pub last_seen: i64, pub last_seen_autocrypt: i64, pub prefer_encrypt: EncryptPreference, - pub public_key: Option, + pub public_key: Option, pub public_key_fingerprint: Option, - pub gossip_key: Option, + pub gossip_key: Option, pub gossip_timestamp: i64, pub gossip_key_fingerprint: Option, - pub verified_key: Option, + pub verified_key: Option, pub verified_key_fingerprint: Option, pub to_save: Option, pub degrade_event: Option, @@ -127,7 +126,7 @@ impl<'a> Peerstate<'a> { res.last_seen_autocrypt = message_time; res.to_save = Some(ToSave::All); res.prefer_encrypt = header.prefer_encrypt; - res.public_key = Some(Key::from(header.public_key.clone())); + res.public_key = Some(header.public_key.clone()); res.recalc_fingerprint(); res @@ -138,7 +137,7 @@ impl<'a> Peerstate<'a> { res.gossip_timestamp = message_time; res.to_save = Some(ToSave::All); - res.gossip_key = Some(Key::from(gossip_header.public_key.clone())); + res.gossip_key = Some(gossip_header.public_key.clone()); res.recalc_fingerprint(); res @@ -220,15 +219,15 @@ impl<'a> Peerstate<'a> { res.public_key = row .get(4) .ok() - .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public).ok()); + .and_then(|blob: Vec| SignedPublicKey::from_slice(&blob).ok()); res.gossip_key = row .get(6) .ok() - .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public).ok()); + .and_then(|blob: Vec| SignedPublicKey::from_slice(&blob).ok()); res.verified_key = row .get(9) .ok() - .and_then(|blob: Vec| Key::from_slice(&blob, KeyType::Public).ok()); + .and_then(|blob: Vec| SignedPublicKey::from_slice(&blob).ok()); Ok(res) }) @@ -239,7 +238,7 @@ impl<'a> Peerstate<'a> { pub fn recalc_fingerprint(&mut self) { if let Some(ref public_key) = self.public_key { let old_public_fingerprint = self.public_key_fingerprint.take(); - self.public_key_fingerprint = Some(public_key.fingerprint()); + self.public_key_fingerprint = Some(public_key.fingerprint().hex()); if old_public_fingerprint.is_none() || self.public_key_fingerprint.is_none() @@ -254,7 +253,7 @@ impl<'a> Peerstate<'a> { if let Some(ref gossip_key) = self.gossip_key { let old_gossip_fingerprint = self.gossip_key_fingerprint.take(); - self.gossip_key_fingerprint = Some(gossip_key.fingerprint()); + self.gossip_key_fingerprint = Some(gossip_key.fingerprint().hex()); if old_gossip_fingerprint.is_none() || self.gossip_key_fingerprint.is_none() @@ -300,8 +299,8 @@ impl<'a> Peerstate<'a> { self.to_save = Some(ToSave::All) } - if self.public_key.as_ref() != Some(&Key::from(header.public_key.clone())) { - self.public_key = Some(Key::from(header.public_key.clone())); + if self.public_key.as_ref() != Some(&header.public_key) { + self.public_key = Some(header.public_key.clone()); self.recalc_fingerprint(); self.to_save = Some(ToSave::All); } @@ -316,9 +315,8 @@ impl<'a> Peerstate<'a> { if message_time > self.gossip_timestamp { self.gossip_timestamp = message_time; self.to_save = Some(ToSave::Timestamps); - let hdr_key = Key::from(gossip_header.public_key.clone()); - if self.gossip_key.as_ref() != Some(&hdr_key) { - self.gossip_key = Some(hdr_key); + if self.gossip_key.as_ref() != Some(&gossip_header.public_key) { + self.gossip_key = Some(gossip_header.public_key.clone()); self.recalc_fingerprint(); self.to_save = Some(ToSave::All) } @@ -367,7 +365,7 @@ impl<'a> Peerstate<'a> { } } - pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option { + pub fn take_key(mut self, min_verified: PeerstateVerifiedStatus) -> Option { match min_verified { PeerstateVerifiedStatus::BidirectVerified => self.verified_key.take(), PeerstateVerifiedStatus::Unverified => { @@ -376,7 +374,7 @@ impl<'a> Peerstate<'a> { } } - pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&Key> { + pub fn peek_key(&self, min_verified: PeerstateVerifiedStatus) -> Option<&SignedPublicKey> { match min_verified { PeerstateVerifiedStatus::BidirectVerified => self.verified_key.as_ref(), PeerstateVerifiedStatus::Unverified => self @@ -495,7 +493,7 @@ mod tests { let ctx = crate::test_utils::dummy_context().await; let addr = "hello@mail.com"; - let pub_key = crate::key::Key::from(alice_keypair().public); + let pub_key = alice_keypair().public; let mut peerstate = Peerstate { context: &ctx.ctx, @@ -504,12 +502,12 @@ mod tests { last_seen_autocrypt: 11, prefer_encrypt: EncryptPreference::Mutual, public_key: Some(pub_key.clone()), - public_key_fingerprint: Some(pub_key.fingerprint()), + public_key_fingerprint: Some(pub_key.fingerprint().hex()), gossip_key: Some(pub_key.clone()), gossip_timestamp: 12, - gossip_key_fingerprint: Some(pub_key.fingerprint()), + gossip_key_fingerprint: Some(pub_key.fingerprint().hex()), verified_key: Some(pub_key.clone()), - verified_key_fingerprint: Some(pub_key.fingerprint()), + verified_key_fingerprint: Some(pub_key.fingerprint().hex()), to_save: Some(ToSave::All), degrade_event: None, }; @@ -527,7 +525,7 @@ mod tests { peerstate.to_save = None; assert_eq!(peerstate, peerstate_new); let peerstate_new2 = - Peerstate::from_fingerprint(&ctx.ctx, &ctx.ctx.sql, &pub_key.fingerprint()) + Peerstate::from_fingerprint(&ctx.ctx, &ctx.ctx.sql, &pub_key.fingerprint().hex()) .await .expect("failed to load peerstate from db"); assert_eq!(peerstate, peerstate_new2); @@ -537,7 +535,7 @@ mod tests { async fn test_peerstate_double_create() { let ctx = crate::test_utils::dummy_context().await; let addr = "hello@mail.com"; - let pub_key = crate::key::Key::from(alice_keypair().public); + let pub_key = alice_keypair().public; let peerstate = Peerstate { context: &ctx.ctx, @@ -546,7 +544,7 @@ mod tests { last_seen_autocrypt: 11, prefer_encrypt: EncryptPreference::Mutual, public_key: Some(pub_key.clone()), - public_key_fingerprint: Some(pub_key.fingerprint()), + public_key_fingerprint: Some(pub_key.fingerprint().hex()), gossip_key: None, gossip_timestamp: 12, gossip_key_fingerprint: None, @@ -571,7 +569,7 @@ mod tests { let ctx = crate::test_utils::dummy_context().await; let addr = "hello@mail.com"; - let pub_key = crate::key::Key::from(alice_keypair().public); + let pub_key = alice_keypair().public; let mut peerstate = Peerstate { context: &ctx.ctx, @@ -580,7 +578,7 @@ mod tests { last_seen_autocrypt: 11, prefer_encrypt: EncryptPreference::Mutual, public_key: Some(pub_key.clone()), - public_key_fingerprint: Some(pub_key.fingerprint()), + public_key_fingerprint: Some(pub_key.fingerprint().hex()), gossip_key: None, gossip_timestamp: 12, gossip_key_fingerprint: None, diff --git a/src/pgp.rs b/src/pgp.rs index fef20379d..21f68f37f 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -240,7 +240,7 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option, private_key_for_signing: Option, ) -> Result { let lit_msg = Message::new_literal_bytes("", plain); @@ -249,7 +249,7 @@ pub async fn pk_encrypt( let pkeys: Vec = public_keys_for_encryption .keys() .iter() - .filter_map(|key| key.try_into().ok().and_then(select_pk_for_encryption)) + .filter_map(|key| select_pk_for_encryption(key)) .collect(); let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect(); @@ -280,19 +280,15 @@ pub async fn pk_encrypt( #[allow(clippy::implicit_hasher)] pub async fn pk_decrypt( ctext: Vec, - private_keys_for_decryption: Keyring, - public_keys_for_validation: Keyring, + private_keys_for_decryption: Keyring, + public_keys_for_validation: Keyring, ret_signature_fingerprints: Option<&mut HashSet>, ) -> Result> { let msgs = async_std::task::spawn_blocking(move || { let cursor = Cursor::new(ctext); let (msg, _) = Message::from_armor_single(cursor)?; - let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption - .keys() - .iter() - .filter_map(|key| key.try_into().ok()) - .collect(); + let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.keys().iter().collect(); let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?; decryptor.collect::>>() @@ -311,15 +307,12 @@ pub async fn pk_decrypt( let fingerprints = async_std::task::spawn_blocking(move || { let dec_msg = &msgs[0]; - let pkeys = public_keys_for_validation - .keys() - .iter() - .filter_map(|key| -> Option<&SignedPublicKey> { key.try_into().ok() }); + let pkeys = public_keys_for_validation.keys(); let mut fingerprints = Vec::new(); for pkey in pkeys { if dec_msg.verify(&pkey.primary_key).is_ok() { - let fp = hex::encode_upper(pkey.fingerprint()); + let fp = DcKey::fingerprint(pkey).hex(); fingerprints.push(fp); } } @@ -424,10 +417,10 @@ mod tests { /// [Key] objects to use in tests. struct TestKeys { - alice_secret: Key, - alice_public: Key, - bob_secret: Key, - bob_public: Key, + alice_secret: SignedSecretKey, + alice_public: SignedPublicKey, + bob_secret: SignedSecretKey, + bob_public: SignedPublicKey, } impl TestKeys { @@ -435,10 +428,10 @@ mod tests { let alice = alice_keypair(); let bob = bob_keypair(); TestKeys { - alice_secret: Key::from(alice.secret.clone()), - alice_public: Key::from(alice.public.clone()), - bob_secret: Key::from(bob.secret.clone()), - bob_public: Key::from(bob.public.clone()), + alice_secret: alice.secret.clone(), + alice_public: alice.public.clone(), + bob_secret: bob.secret.clone(), + bob_public: bob.public.clone(), } } } @@ -452,15 +445,15 @@ mod tests { /// A cyphertext encrypted to Alice & Bob, signed by Alice. static ref CTEXT_SIGNED: String = { - let mut keyring = Keyring::default(); + let mut keyring = Keyring::new(); keyring.add(KEYS.alice_public.clone()); keyring.add(KEYS.bob_public.clone()); - smol::block_on(pk_encrypt(CLEARTEXT, keyring, Some(KEYS.alice_secret.clone()))).unwrap() + smol::block_on(pk_encrypt(CLEARTEXT, keyring, Some(Key::from(KEYS.alice_secret.clone())))).unwrap() }; /// A cyphertext encrypted to Alice & Bob, not signed. static ref CTEXT_UNSIGNED: String = { - let mut keyring = Keyring::default(); + let mut keyring = Keyring::new(); keyring.add(KEYS.alice_public.clone()); keyring.add(KEYS.bob_public.clone()); smol::block_on(pk_encrypt(CLEARTEXT, keyring, None)).unwrap() @@ -482,9 +475,9 @@ mod tests { #[async_std::test] async fn test_decrypt_singed() { // Check decrypting as Alice - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring: Keyring = Keyring::new(); decrypt_keyring.add(KEYS.alice_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring: Keyring = Keyring::new(); sig_check_keyring.add(KEYS.alice_public.clone()); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( @@ -500,9 +493,9 @@ mod tests { assert_eq!(valid_signatures.len(), 1); // Check decrypting as Bob - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring = Keyring::new(); sig_check_keyring.add(KEYS.alice_public.clone()); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( @@ -520,9 +513,9 @@ mod tests { #[async_std::test] async fn test_decrypt_no_sig_check() { - let mut keyring = Keyring::default(); + let mut keyring = Keyring::new(); keyring.add(KEYS.alice_secret.clone()); - let empty_keyring = Keyring::default(); + let empty_keyring = Keyring::new(); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( CTEXT_SIGNED.as_bytes().to_vec(), @@ -539,9 +532,9 @@ mod tests { #[async_std::test] async fn test_decrypt_signed_no_key() { // The validation does not have the public key of the signer. - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring = Keyring::new(); sig_check_keyring.add(KEYS.bob_public.clone()); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( @@ -558,10 +551,9 @@ mod tests { #[async_std::test] async fn test_decrypt_unsigned() { - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let sig_check_keyring = Keyring::default(); - decrypt_keyring.add(KEYS.alice_public.clone()); + let sig_check_keyring = Keyring::new(); let mut valid_signatures: HashSet = Default::default(); let plain = pk_decrypt( CTEXT_UNSIGNED.as_bytes().to_vec(), @@ -578,9 +570,9 @@ mod tests { #[async_std::test] async fn test_decrypt_signed_no_sigret() { // Check decrypting signed cyphertext without providing the HashSet for signatures. - let mut decrypt_keyring = Keyring::default(); + let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); - let mut sig_check_keyring = Keyring::default(); + let mut sig_check_keyring = Keyring::new(); sig_check_keyring.add(KEYS.alice_public.clone()); let plain = pk_decrypt( CTEXT_SIGNED.as_bytes().to_vec(), diff --git a/src/securejoin.rs b/src/securejoin.rs index 580238881..163516bb5 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -14,7 +14,7 @@ use crate::e2ee::*; use crate::error::{bail, Error}; use crate::events::Event; use crate::headerdef::HeaderDef; -use crate::key::{dc_normalize_fingerprint, DcKey, Key, SignedPublicKey}; +use crate::key::{dc_normalize_fingerprint, DcKey, SignedPublicKey}; use crate::lot::LotState; use crate::message::Message; use crate::mimeparser::*; @@ -142,7 +142,7 @@ pub async fn dc_get_securejoin_qr(context: &Context, group_chat_id: ChatId) -> O async fn get_self_fingerprint(context: &Context) -> Option { match SignedPublicKey::load_self(context).await { - Ok(key) => Some(Key::from(key).fingerprint()), + Ok(key) => Some(key.fingerprint().hex()), Err(_) => { warn!(context, "get_self_fingerprint(): failed to load key"); None