mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 10:26:29 +03:00
Finish Key->DcKey refactoring
Migrates .verify() and .split_key() to DcKey. Removes all remaining uses of Key.
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
21
src/imex.rs
21
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,
|
||||
|
||||
106
src/key.rs
106
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<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> {
|
||||
let addr = context
|
||||
.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.
|
||||
///
|
||||
/// 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]
|
||||
|
||||
15
src/pgp.rs
15
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<SignedPublicKeyOrSu
|
||||
pub async fn pk_encrypt(
|
||||
plain: &[u8],
|
||||
public_keys_for_encryption: Keyring<SignedPublicKey>,
|
||||
private_key_for_signing: Option<Key>,
|
||||
private_key_for_signing: Option<SignedSecretKey>,
|
||||
) -> Result<String> {
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user