Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] experiment: partial port to rpgp with new v6 API #5880

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 16 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ async-native-tls = { version = "0.5", default-features = false, features = ["run
async-smtp = { version = "0.9", default-features = false, features = ["runtime-tokio"] }
async_zip = { version = "0.0.12", default-features = false, features = ["deflate", "fs"] }
base64 = { workspace = true }
brotli = { version = "6", default-features=false, features = ["std"] }
brotli = { version = "6", default-features = false, features = ["std"] }
chrono = { workspace = true, features = ["alloc", "clock", "std"] }
email = { git = "https://github.com/deltachat/rust-email", branch = "master" }
encoded-words = { git = "https://github.com/async-email/encoded-words", branch = "master" }
Expand All @@ -58,8 +58,8 @@ futures-lite = { workspace = true }
hex = "0.4.0"
hickory-resolver = "0.24"
humansize = "2"
image = { version = "0.25.1", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
iroh_old = { version = "0.4.2", default-features = false, package = "iroh"}
image = { version = "0.25.1", default-features = false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
iroh_old = { version = "0.4.2", default-features = false, package = "iroh" }
iroh-net = { version = "0.22.0", default-features = false }
iroh-gossip = { version = "0.22.0", default-features = false, features = ["net"] }
kamadak-exif = "0.5.3"
Expand All @@ -73,7 +73,7 @@ num-traits = { workspace = true }
once_cell = { workspace = true }
percent-encoding = "2.3"
parking_lot = "0.12"
pgp = { version = "0.13", default-features = false }
pgp = { git = "https://github.com/hko-s/rpgp.git", branch = "rfc9580-keys" }
qrcodegen = "1.7.0"
quick-xml = "0.36"
quoted_printable = "0.5"
Expand Down Expand Up @@ -115,15 +115,15 @@ pretty_assertions = "1.3.0"

[workspace]
members = [
"deltachat-ffi",
"deltachat_derive",
"deltachat-jsonrpc",
"deltachat-rpc-server",
"deltachat-ratelimit",
"deltachat-repl",
"deltachat-time",
"format-flowed",
"deltachat-contact-tools",
"deltachat-ffi",
"deltachat_derive",
"deltachat-jsonrpc",
"deltachat-rpc-server",
"deltachat-ratelimit",
"deltachat-repl",
"deltachat-time",
"format-flowed",
"deltachat-contact-tools",
]

[[bench]]
Expand Down Expand Up @@ -193,9 +193,9 @@ yerpc = "0.6.2"
default = ["vendored"]
internals = []
vendored = [
"async-native-tls/vendored",
"rusqlite/bundled-sqlcipher-vendored-openssl",
"reqwest/native-tls-vendored"
"async-native-tls/vendored",
"rusqlite/bundled-sqlcipher-vendored-openssl",
"reqwest/native-tls-vendored"
]

[lints.rust]
Expand Down
5 changes: 3 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::time::Duration;

use anyhow::{bail, ensure, Context as _, Result};
use async_channel::{self as channel, Receiver, Sender};
use pgp::types::PublicKeyTrait;
use pgp::SignedPublicKey;
use ratelimit::Ratelimit;
use tokio::sync::{Mutex, Notify, OnceCell, RwLock};
Expand Down Expand Up @@ -748,7 +749,7 @@ impl Context {
.count("SELECT COUNT(*) FROM acpeerstates;", ())
.await?;
let fingerprint_str = match load_self_public_key(self).await {
Ok(key) => key.fingerprint().hex(),
Ok(key) => crate::key::DcKey::fingerprint(&key).hex(),
Err(err) => format!("<key failure: {err}>"),
};

Expand Down Expand Up @@ -1132,7 +1133,7 @@ impl Context {
EncryptPreference::Mutual,
&public_key,
);
let fingerprint = public_key.fingerprint();
let fingerprint = crate::key::DcKey::fingerprint(&public_key);
peerstate.set_verified(public_key, fingerprint, "".to_string())?;
peerstate.save_to_db(&self.sql).await?;
chat_id
Expand Down
2 changes: 1 addition & 1 deletion src/imex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::ffi::OsStr;
use std::path::{Path, PathBuf};

use ::pgp::types::KeyTrait;
use ::pgp::types::PublicKeyTrait;
use anyhow::{bail, ensure, format_err, Context as _, Result};
use deltachat_contact_tools::EmailAddress;
use futures::TryStreamExt;
Expand Down
16 changes: 8 additions & 8 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use num_traits::FromPrimitive;
use pgp::composed::Deserializable;
pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
use pgp::ser::Serialize;
use pgp::types::{KeyTrait, SecretKeyTrait};
use pgp::types::{PublicKeyTrait, SecretKeyTrait};
use rand::thread_rng;
use tokio::runtime::Handle;

use crate::config::Config;
Expand All @@ -26,7 +27,7 @@ use crate::tools::{self, time_elapsed};
/// This trait is implemented for rPGP's [SignedPublicKey] and
/// [SignedSecretKey] types and makes working with them a little
/// easier in the deltachat world.
pub(crate) trait DcKey: Serialize + Deserializable + KeyTrait + Clone {
pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone {
/// Create a key from some bytes.
fn from_slice(bytes: &[u8]) -> Result<Self> {
Ok(<Self as Deserializable>::from_bytes(Cursor::new(bytes))?)
Expand Down Expand Up @@ -94,7 +95,7 @@ pub(crate) trait DcKey: Serialize + Deserializable + KeyTrait + Clone {

/// The fingerprint for the key.
fn fingerprint(&self) -> Fingerprint {
Fingerprint::new(KeyTrait::fingerprint(self))
Fingerprint::new(PublicKeyTrait::fingerprint(self))
}

fn is_private() -> bool;
Expand Down Expand Up @@ -233,7 +234,7 @@ 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())?;
let signed_pubkey = unsigned_pubkey.sign(thread_rng(), self, || "".into())?;
Ok(signed_pubkey)
}
}
Expand Down Expand Up @@ -392,12 +393,11 @@ pub async fn preconfigure_keypair(context: &Context, addr: &str, secret_data: &s

/// A key fingerprint
#[derive(Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub struct Fingerprint(Vec<u8>);
pub struct Fingerprint(pgp::types::Fingerprint);

impl Fingerprint {
/// Creates new 160-bit (20 bytes) fingerprint.
pub fn new(v: Vec<u8>) -> Fingerprint {
debug_assert_eq!(v.len(), 20);
/// Creates new fingerprint.
pub fn new(v: pgp::types::Fingerprint) -> Fingerprint {
Fingerprint(v)
}

Expand Down
2 changes: 1 addition & 1 deletion src/peerstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ impl Peerstate {
pub fn set_verified(
&mut self,
key: SignedPublicKey,
fingerprint: Fingerprint,
fingerprint: crate::key::Fingerprint,
verifier: String,
) -> Result<()> {
if key.fingerprint() == fingerprint {
Expand Down
54 changes: 34 additions & 20 deletions src/pgp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::io;
use std::io::Cursor;

use anyhow::{bail, Context as _, Result};
use chrono::{DateTime, Utc};
use deltachat_contact_tools::EmailAddress;
use pgp::armor::BlockType;
use pgp::composed::{
Expand All @@ -15,7 +16,8 @@ use pgp::crypto::ecc_curve::ECCCurve;
use pgp::crypto::hash::HashAlgorithm;
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::types::{
CompressionAlgorithm, KeyTrait, Mpi, PublicKeyTrait, SecretKeyTrait, StringToKey,
CompressionAlgorithm, KeyVersion, Mpi, PublicKeyTrait, PublicParams, SecretKeyTrait,
SignatureBytes, StringToKey,
};
use rand::{thread_rng, CryptoRng, Rng};
use tokio::runtime::Handle;
Expand Down Expand Up @@ -43,8 +45,8 @@ enum SignedPublicKeyOrSubkey<'a> {
Subkey(&'a SignedPublicSubKey),
}

impl<'a> KeyTrait for SignedPublicKeyOrSubkey<'a> {
fn fingerprint(&self) -> Vec<u8> {
impl<'a> PublicKeyTrait for SignedPublicKeyOrSubkey<'a> {
fn fingerprint(&self) -> pgp::types::Fingerprint {
match self {
Self::Key(k) => k.fingerprint(),
Self::Subkey(k) => k.fingerprint(),
Expand All @@ -64,38 +66,48 @@ impl<'a> KeyTrait for SignedPublicKeyOrSubkey<'a> {
Self::Subkey(k) => k.algorithm(),
}
}
}

impl<'a> PublicKeyTrait for SignedPublicKeyOrSubkey<'a> {
fn verify_signature(
&self,
hash: HashAlgorithm,
data: &[u8],
sig: &[Mpi],
sig: &SignatureBytes,
) -> pgp::errors::Result<()> {
match self {
Self::Key(k) => k.verify_signature(hash, data, sig),
Self::Subkey(k) => k.verify_signature(hash, data, sig),
}
}

fn encrypt<R: Rng + CryptoRng>(
&self,
rng: &mut R,
plain: &[u8],
) -> pgp::errors::Result<Vec<Mpi>> {
fn encrypt<R: Rng + CryptoRng>(&self, rng: R, plain: &[u8]) -> pgp::errors::Result<Vec<Mpi>> {
match self {
Self::Key(k) => k.encrypt(rng, plain),
Self::Subkey(k) => k.encrypt(rng, plain),
}
}

fn to_writer_old(&self, writer: &mut impl io::Write) -> pgp::errors::Result<()> {
fn serialize_for_hashing(&self, writer: &mut impl io::Write) -> pgp::errors::Result<()> {
match self {
Self::Key(k) => k.to_writer_old(writer),
Self::Subkey(k) => k.to_writer_old(writer),
Self::Key(k) => k.serialize_for_hashing(writer),
Self::Subkey(k) => k.serialize_for_hashing(writer),
}
}

fn version(&self) -> KeyVersion {
todo!()
}

fn created_at(&self) -> &DateTime<Utc> {
todo!()
}

fn expiration(&self) -> Option<u16> {
todo!()
}

fn public_params(&self) -> &PublicParams {
todo!()
}
}

/// Split data from PGP Armored Data as defined in <https://tools.ietf.org/html/rfc4880#section-6.2>.
Expand Down Expand Up @@ -153,9 +165,10 @@ pub(crate) fn create_keypair(addr: EmailAddress, keygen_type: KeyGenType) -> Res
let (signing_key_type, encryption_key_type) = match keygen_type {
KeyGenType::Rsa2048 => (PgpKeyType::Rsa(2048), PgpKeyType::Rsa(2048)),
KeyGenType::Rsa4096 => (PgpKeyType::Rsa(4096), PgpKeyType::Rsa(4096)),
KeyGenType::Ed25519 | KeyGenType::Default => {
(PgpKeyType::EdDSA, PgpKeyType::ECDH(ECCCurve::Curve25519))
}
KeyGenType::Ed25519 | KeyGenType::Default => (
PgpKeyType::EdDSALegacy,
PgpKeyType::ECDH(ECCCurve::Curve25519),
),
};

let user_id = format!("<{addr}>");
Expand Down Expand Up @@ -195,15 +208,15 @@ pub(crate) fn create_keypair(addr: EmailAddress, keygen_type: KeyGenType) -> Res
let secret_key = key_params
.generate()
.context("failed to generate the key")?
.sign(|| "".into())
.sign(thread_rng(), || "".into())
.context("failed to sign secret key")?;
secret_key
.verify()
.context("invalid secret key generated")?;

let public_key = secret_key
.public_key()
.sign(&secret_key, || "".into())
.sign(thread_rng(), &secret_key, || "".into())
.context("failed to sign public key")?;
public_key
.verify()
Expand Down Expand Up @@ -261,7 +274,7 @@ pub async fn pk_encrypt(
let mut rng = thread_rng();

let encrypted_msg = if let Some(ref skey) = private_key_for_signing {
let signed_msg = lit_msg.sign(skey, || "".into(), HASH_ALGORITHM)?;
let signed_msg = lit_msg.sign(thread_rng(), skey, || "".into(), HASH_ALGORITHM)?;
let compressed_msg = if compress {
signed_msg.compress(CompressionAlgorithm::ZLIB)?
} else {
Expand All @@ -285,6 +298,7 @@ pub fn pk_calc_signature(
private_key_for_signing: &SignedSecretKey,
) -> Result<String> {
let msg = Message::new_literal_bytes("", plain).sign(
thread_rng(),
private_key_for_signing,
|| "".into(),
HASH_ALGORITHM,
Expand Down
Loading