Finish Key->DcKey refactoring

Migrates .verify() and .split_key() to DcKey.  Removes all remaining
uses of Key.
This commit is contained in:
Floris Bruynooghe
2020-05-17 16:09:10 +02:00
parent cdbd3d7d84
commit a236a619ad
4 changed files with 31 additions and 115 deletions

View File

@@ -11,7 +11,7 @@ use crate::context::Context;
use crate::error::*; use crate::error::*;
use crate::headerdef::HeaderDef; use crate::headerdef::HeaderDef;
use crate::headerdef::HeaderDefMap; use crate::headerdef::HeaderDefMap;
use crate::key::{DcKey, Key, SignedPublicKey, SignedSecretKey}; use crate::key::{DcKey, SignedPublicKey, SignedSecretKey};
use crate::keyring::*; use crate::keyring::*;
use crate::peerstate::*; use crate::peerstate::*;
use crate::pgp; use crate::pgp;
@@ -105,7 +105,7 @@ impl EncryptHelper {
keyring.add(key); keyring.add(key);
} }
keyring.add(self.public_key.clone()); 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(); let raw_message = mail_to_encrypt.build().as_string().into_bytes();

View File

@@ -17,7 +17,7 @@ use crate::dc_tools::*;
use crate::e2ee; use crate::e2ee;
use crate::error::*; use crate::error::*;
use crate::events::Event; 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::message::{Message, MsgId};
use crate::mimeparser::SystemMessage; use crate::mimeparser::SystemMessage;
use crate::param::*; use crate::param::*;
@@ -292,14 +292,8 @@ async fn set_self_key(
prefer_encrypt_required: bool, prefer_encrypt_required: bool,
) -> Result<()> { ) -> Result<()> {
// try hard to only modify key-state // try hard to only modify key-state
let keys = SignedSecretKey::from_asc(armored) let (private_key, header) = SignedSecretKey::from_asc(armored)?;
.map(|(key, hdrs)| (Key::from(key), hdrs)) let public_key = private_key.split_public_key()?;
.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 preferencrypt = header.get("Autocrypt-Prefer-Encrypt"); let preferencrypt = header.get("Autocrypt-Prefer-Encrypt");
match preferencrypt.map(|s| s.as_str()) { match preferencrypt.map(|s| s.as_str()) {
Some(headerval) => { Some(headerval) => {
@@ -325,15 +319,10 @@ async fn set_self_key(
let self_addr = context.get_config(Config::ConfiguredAddr).await; let self_addr = context.get_config(Config::ConfiguredAddr).await;
ensure!(self_addr.is_some(), "Missing self addr"); ensure!(self_addr.is_some(), "Missing self addr");
let addr = EmailAddress::new(&self_addr.unwrap_or_default())?; 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 { let keypair = pgp::KeyPair {
addr, addr,
public, public: public_key,
secret, secret: private_key,
}; };
key::store_self_keypair( key::store_self_keypair(
context, context,

View File

@@ -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<SignedPublicKey>;
}
impl DcSecretKey for SignedSecretKey {
fn split_public_key(&self) -> Result<SignedPublicKey> {
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<KeyPair> { async fn generate_keypair(context: &Context) -> Result<KeyPair> {
let addr = context let addr = context
.get_config(Config::ConfiguredAddr) .get_config(Config::ConfiguredAddr)
@@ -248,88 +265,6 @@ async fn generate_keypair(context: &Context) -> Result<KeyPair> {
} }
} }
/// Cryptographic key
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Key {
Public(SignedPublicKey),
Secret(SignedSecretKey),
}
impl From<SignedPublicKey> for Key {
fn from(key: SignedPublicKey) -> Self {
Key::Public(key)
}
}
impl From<SignedSecretKey> for Key {
fn from(key: SignedSecretKey) -> Self {
Key::Secret(key)
}
}
impl std::convert::TryFrom<Key> for SignedSecretKey {
type Error = ();
fn try_from(value: Key) -> std::result::Result<Self, Self::Error> {
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<Self, Self::Error> {
match value {
Key::Public(_) => Err(()),
Key::Secret(key) => Ok(key),
}
}
}
impl std::convert::TryFrom<Key> for SignedPublicKey {
type Error = ();
fn try_from(value: Key) -> std::result::Result<Self, Self::Error> {
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<Self, Self::Error> {
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<Key> {
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. /// Use of a [KeyPair] for encryption or decryption.
/// ///
/// This is used by [store_self_keypair] to know what kind of key is /// 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 { mod tests {
use super::*; use super::*;
use crate::test_utils::*; use crate::test_utils::*;
use std::convert::TryFrom;
use async_std::sync::Arc; use async_std::sync::Arc;
use lazy_static::lazy_static; use lazy_static::lazy_static;
@@ -699,10 +633,8 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[test] #[test]
fn test_split_key() { fn test_split_key() {
let private_key = Key::from(KEYPAIR.secret.clone()); let pubkey = KEYPAIR.secret.split_public_key().unwrap();
let public_wrapped = private_key.split_key().unwrap(); assert_eq!(pubkey.primary_key, KEYPAIR.public.primary_key);
let public = SignedPublicKey::try_from(public_wrapped).unwrap();
assert_eq!(public.primary_key, KEYPAIR.public.primary_key);
} }
#[async_std::test] #[async_std::test]

View File

@@ -1,7 +1,6 @@
//! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp) //! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp)
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::convert::TryInto;
use std::io; use std::io;
use std::io::Cursor; use std::io::Cursor;
@@ -19,8 +18,8 @@ use rand::{thread_rng, CryptoRng, Rng};
use crate::constants::KeyGenType; use crate::constants::KeyGenType;
use crate::dc_tools::EmailAddress; use crate::dc_tools::EmailAddress;
use crate::error::{bail, ensure, format_err, Result}; use crate::error::{bail, ensure, format_err, Result};
use crate::key::*; use crate::key::DcKey;
use crate::keyring::*; use crate::keyring::Keyring;
pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt"; pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt";
pub const HEADER_SETUPCODE: &str = "passphrase-begin"; pub const HEADER_SETUPCODE: &str = "passphrase-begin";
@@ -241,7 +240,7 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<SignedPublicKeyOrSu
pub async fn pk_encrypt( pub async fn pk_encrypt(
plain: &[u8], plain: &[u8],
public_keys_for_encryption: Keyring<SignedPublicKey>, public_keys_for_encryption: Keyring<SignedPublicKey>,
private_key_for_signing: Option<Key>, private_key_for_signing: Option<SignedSecretKey>,
) -> Result<String> { ) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain); let lit_msg = Message::new_literal_bytes("", plain);
@@ -256,11 +255,7 @@ pub async fn pk_encrypt(
let mut rng = thread_rng(); let mut rng = thread_rng();
// TODO: measure time // TODO: measure time
let encrypted_msg = if let Some(ref private_key) = private_key_for_signing { let encrypted_msg = if let Some(ref skey) = private_key_for_signing {
let skey: &SignedSecretKey = private_key
.try_into()
.map_err(|_| format_err!("Invalid private key"))?;
lit_msg lit_msg
.sign(skey, || "".into(), Default::default()) .sign(skey, || "".into(), Default::default())
.and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB)) .and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB))
@@ -448,7 +443,7 @@ mod tests {
let mut keyring = Keyring::new(); let mut keyring = Keyring::new();
keyring.add(KEYS.alice_public.clone()); keyring.add(KEYS.alice_public.clone());
keyring.add(KEYS.bob_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. /// A cyphertext encrypted to Alice & Bob, not signed.