diff --git a/src/e2ee.rs b/src/e2ee.rs index bd20279cc..09915a5b3 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -11,7 +11,7 @@ use crate::context::Context; use crate::error::*; use crate::headerdef::HeaderDef; use crate::headerdef::HeaderDefMap; -use crate::key::{DcKey, Key, SignedPublicKey, SignedSecretKey}; +use crate::key::{DcKey, SignedPublicKey, SignedSecretKey}; use crate::keyring::*; use crate::peerstate::*; use crate::pgp; @@ -105,7 +105,7 @@ impl EncryptHelper { keyring.add(key); } keyring.add(self.public_key.clone()); - let sign_key = Key::from(SignedSecretKey::load_self(context).await?); + let sign_key = SignedSecretKey::load_self(context).await?; let raw_message = mail_to_encrypt.build().as_string().into_bytes(); diff --git a/src/imex.rs b/src/imex.rs index c8e7bd66c..5dc33d05c 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -17,7 +17,7 @@ use crate::dc_tools::*; use crate::e2ee; use crate::error::*; use crate::events::Event; -use crate::key::{self, DcKey, Key, SignedPublicKey, SignedSecretKey}; +use crate::key::{self, DcKey, DcSecretKey, SignedPublicKey, SignedSecretKey}; use crate::message::{Message, MsgId}; use crate::mimeparser::SystemMessage; use crate::param::*; @@ -292,14 +292,8 @@ async fn set_self_key( prefer_encrypt_required: bool, ) -> Result<()> { // try hard to only modify key-state - let keys = SignedSecretKey::from_asc(armored) - .map(|(key, hdrs)| (Key::from(key), hdrs)) - .ok() - .and_then(|(k, h)| if k.verify() { Some((k, h)) } else { None }) - .and_then(|(k, h)| k.split_key().map(|pub_key| (k, pub_key, h))); - - ensure!(keys.is_some(), "Not a valid private key"); - let (private_key, public_key, header) = keys.unwrap(); + let (private_key, header) = SignedSecretKey::from_asc(armored)?; + let public_key = private_key.split_public_key()?; let preferencrypt = header.get("Autocrypt-Prefer-Encrypt"); match preferencrypt.map(|s| s.as_str()) { Some(headerval) => { @@ -325,15 +319,10 @@ async fn set_self_key( let self_addr = context.get_config(Config::ConfiguredAddr).await; ensure!(self_addr.is_some(), "Missing self addr"); let addr = EmailAddress::new(&self_addr.unwrap_or_default())?; - - let (public, secret) = match (public_key, private_key) { - (Key::Public(p), Key::Secret(s)) => (p, s), - _ => bail!("wrong keys unpacked"), - }; let keypair = pgp::KeyPair { addr, - public, - secret, + public: public_key, + secret: private_key, }; key::store_self_keypair( context, diff --git a/src/key.rs b/src/key.rs index cf0399406..8f746bb1f 100644 --- a/src/key.rs +++ b/src/key.rs @@ -200,6 +200,23 @@ impl DcKey for SignedSecretKey { } } +/// Deltachat extension trait for secret keys. +/// +/// Provides some convenience wrappers only applicable to [SignedSecretKey]. +pub trait DcSecretKey { + /// Create a public key from a private one. + fn split_public_key(&self) -> Result; +} + +impl DcSecretKey for SignedSecretKey { + fn split_public_key(&self) -> Result { + self.verify()?; + let unsigned_pubkey = SecretKeyTrait::public_key(self); + let signed_pubkey = unsigned_pubkey.sign(self, || "".into())?; + Ok(signed_pubkey) + } +} + async fn generate_keypair(context: &Context) -> Result { let addr = context .get_config(Config::ConfiguredAddr) @@ -248,88 +265,6 @@ async fn generate_keypair(context: &Context) -> Result { } } -/// Cryptographic key -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Key { - Public(SignedPublicKey), - Secret(SignedSecretKey), -} - -impl From for Key { - fn from(key: SignedPublicKey) -> Self { - Key::Public(key) - } -} - -impl From for Key { - fn from(key: SignedSecretKey) -> Self { - Key::Secret(key) - } -} - -impl std::convert::TryFrom for SignedSecretKey { - type Error = (); - - fn try_from(value: Key) -> std::result::Result { - match value { - Key::Public(_) => Err(()), - Key::Secret(key) => Ok(key), - } - } -} - -impl<'a> std::convert::TryFrom<&'a Key> for &'a SignedSecretKey { - type Error = (); - - fn try_from(value: &'a Key) -> std::result::Result { - match value { - Key::Public(_) => Err(()), - Key::Secret(key) => Ok(key), - } - } -} - -impl std::convert::TryFrom for SignedPublicKey { - type Error = (); - - fn try_from(value: Key) -> std::result::Result { - match value { - Key::Public(key) => Ok(key), - Key::Secret(_) => Err(()), - } - } -} - -impl<'a> std::convert::TryFrom<&'a Key> for &'a SignedPublicKey { - type Error = (); - - fn try_from(value: &'a Key) -> std::result::Result { - match value { - Key::Public(key) => Ok(key), - Key::Secret(_) => Err(()), - } - } -} - -impl Key { - pub fn verify(&self) -> bool { - match self { - Key::Public(k) => k.verify().is_ok(), - Key::Secret(k) => k.verify().is_ok(), - } - } - - pub fn split_key(&self) -> Option { - match self { - Key::Public(_) => None, - Key::Secret(k) => { - let pub_key = k.public_key(); - pub_key.sign(k, || "".into()).map(Key::Public).ok() - } - } - } -} - /// Use of a [KeyPair] for encryption or decryption. /// /// This is used by [store_self_keypair] to know what kind of key is @@ -496,7 +431,6 @@ pub fn dc_format_fingerprint(fingerprint: &str) -> String { mod tests { use super::*; use crate::test_utils::*; - use std::convert::TryFrom; use async_std::sync::Arc; use lazy_static::lazy_static; @@ -699,10 +633,8 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD #[test] fn test_split_key() { - let private_key = Key::from(KEYPAIR.secret.clone()); - let public_wrapped = private_key.split_key().unwrap(); - let public = SignedPublicKey::try_from(public_wrapped).unwrap(); - assert_eq!(public.primary_key, KEYPAIR.public.primary_key); + let pubkey = KEYPAIR.secret.split_public_key().unwrap(); + assert_eq!(pubkey.primary_key, KEYPAIR.public.primary_key); } #[async_std::test] diff --git a/src/pgp.rs b/src/pgp.rs index 21f68f37f..0c4a54c08 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -1,7 +1,6 @@ //! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp) use std::collections::{BTreeMap, HashSet}; -use std::convert::TryInto; use std::io; use std::io::Cursor; @@ -19,8 +18,8 @@ use rand::{thread_rng, CryptoRng, Rng}; use crate::constants::KeyGenType; use crate::dc_tools::EmailAddress; use crate::error::{bail, ensure, format_err, Result}; -use crate::key::*; -use crate::keyring::*; +use crate::key::DcKey; +use crate::keyring::Keyring; pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt"; pub const HEADER_SETUPCODE: &str = "passphrase-begin"; @@ -241,7 +240,7 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option, - private_key_for_signing: Option, + private_key_for_signing: Option, ) -> Result { let lit_msg = Message::new_literal_bytes("", plain); @@ -256,11 +255,7 @@ pub async fn pk_encrypt( let mut rng = thread_rng(); // TODO: measure time - let encrypted_msg = if let Some(ref private_key) = private_key_for_signing { - let skey: &SignedSecretKey = private_key - .try_into() - .map_err(|_| format_err!("Invalid private key"))?; - + let encrypted_msg = if let Some(ref skey) = private_key_for_signing { lit_msg .sign(skey, || "".into(), Default::default()) .and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB)) @@ -448,7 +443,7 @@ mod tests { 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(Key::from(KEYS.alice_secret.clone())))).unwrap() + smol::block_on(pk_encrypt(CLEARTEXT, keyring, Some(KEYS.alice_secret.clone()))).unwrap() }; /// A cyphertext encrypted to Alice & Bob, not signed.