Skip to content

xx: partial port to rpgp main #6717

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

Closed
wants to merge 1 commit into from
Closed
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
1,494 changes: 851 additions & 643 deletions Cargo.lock

Large diffs are not rendered by default.

28 changes: 14 additions & 14 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.10", default-features = false, features = ["runtime-tokio"] }
async_zip = { version = "0.0.17", default-features = false, features = ["deflate", "tokio-fs"] }
base64 = { workspace = true }
brotli = { version = "7", default-features=false, features = ["std"] }
brotli = { version = "7", default-features = false, features = ["std"] }
bytes = "1"
chrono = { workspace = true, features = ["alloc", "clock", "std"] }
data-encoding = "2.7.0"
Expand All @@ -61,7 +61,7 @@ http-body-util = "0.1.2"
humansize = "2"
hyper = "1"
hyper-util = "0.1.10"
image = { version = "0.25.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
image = { version = "0.25.5", default-features = false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
iroh-gossip = { version = "0.33", default-features = false, features = ["net"] }
iroh = { version = "0.33", default-features = false }
kamadak-exif = "0.6.1"
Expand All @@ -75,7 +75,7 @@ num-traits = { workspace = true }
once_cell = { workspace = true }
parking_lot = "0.12"
percent-encoding = "2.3"
pgp = { version = "0.15.0", default-features = false }
pgp = { git = "https://github.com/rpgp/rpgp.git" }
pin-project = "1"
qrcodegen = "1.7.0"
quick-xml = "0.37"
Expand Down Expand Up @@ -125,16 +125,16 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

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

[[bench]]
Expand Down Expand Up @@ -203,7 +203,7 @@ yerpc = "0.6.2"
default = ["vendored"]
internals = []
vendored = [
"rusqlite/bundled-sqlcipher-vendored-openssl"
"rusqlite/bundled-sqlcipher-vendored-openssl"
]

[lints.rust]
Expand Down
2 changes: 1 addition & 1 deletion src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ impl Context {
res += &format!("db_size_bytes {}\n", db_size);

let secret_key = &load_self_secret_key(self).await?.primary_key;
let key_created = secret_key.created_at().timestamp();
let key_created = secret_key.public_key().created_at().timestamp();
res += &format!("key_created {}\n", key_created);

// how many of the chats active in the last months are:
Expand Down
8 changes: 4 additions & 4 deletions src/decrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ use crate::pgp;
/// Tries to decrypt a message, but only if it is structured as an Autocrypt message.
///
/// If successful and the message is encrypted, returns decrypted body.
pub fn try_decrypt(
mail: &ParsedMail<'_>,
private_keyring: &[SignedSecretKey],
) -> Result<Option<::pgp::composed::Message>> {
pub fn try_decrypt<'a>(
mail: &'a ParsedMail<'a>,
private_keyring: &'a [SignedSecretKey],
) -> Result<Option<::pgp::composed::Message<'a>>> {
let Some(encrypted_data_part) = get_encrypted_mime(mail) else {
return Ok(None);
};
Expand Down
8 changes: 6 additions & 2 deletions src/imex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::pin::Pin;

use ::pgp::types::PublicKeyTrait;
use anyhow::{bail, ensure, format_err, Context as _, Result};
use futures::TryStreamExt;
use futures_lite::FutureExt;
Expand Down Expand Up @@ -32,6 +31,7 @@ use crate::tools::{
mod key_transfer;
mod transfer;

use ::pgp::types::KeyDetails;
pub use key_transfer::{continue_key_transfer, initiate_key_transfer};
pub use transfer::{get_backup, BackupProvider};

Expand Down Expand Up @@ -173,7 +173,11 @@ async fn set_self_key(context: &Context, armored: &str) -> Result<()> {
};
key::store_self_keypair(context, &keypair).await?;

info!(context, "stored self key: {:?}", keypair.secret.key_id());
info!(
context,
"stored self key: {:?}",
keypair.secret.public_key().key_id()
);
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion src/imex/key_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fn create_setup_code(_context: &Context) -> String {
ret
}

async fn decrypt_setup_file<T: std::io::Read + std::io::Seek>(
async fn decrypt_setup_file<T: std::io::Read + std::fmt::Debug + std::io::BufRead>(
passphrase: &str,
file: T,
) -> Result<String> {
Expand Down
15 changes: 10 additions & 5 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use deltachat_contact_tools::EmailAddress;
use pgp::composed::Deserializable;
pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
use pgp::ser::Serialize;
use pgp::types::{PublicKeyTrait, SecretKeyTrait};
use pgp::types::{Password, PublicKeyTrait};
use rand::thread_rng;
use tokio::runtime::Handle;

Expand Down Expand Up @@ -78,7 +78,7 @@ pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone {
let bytes = data.as_bytes();
let res = Self::from_armor_single(Cursor::new(bytes));
let (key, headers) = match res {
Err(pgp::errors::Error::NoMatchingPacket) => match Self::is_private() {
Err(pgp::errors::Error::NoMatchingPacket { .. }) => match Self::is_private() {
true => bail!("No private key packet found"),
false => bail!("No public key packet found"),
},
Expand Down Expand Up @@ -124,7 +124,7 @@ pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone {

/// The fingerprint for the key.
fn dc_fingerprint(&self) -> Fingerprint {
PublicKeyTrait::fingerprint(self).into()
<dyn PublicKeyTrait>::fingerprint(self).into()
}

fn is_private() -> bool;
Expand Down Expand Up @@ -262,9 +262,14 @@ pub(crate) trait DcSecretKey {
impl DcSecretKey for SignedSecretKey {
fn split_public_key(&self) -> Result<SignedPublicKey> {
self.verify()?;
let unsigned_pubkey = SecretKeyTrait::public_key(self);
let unsigned_pubkey = self.public_key();
let mut rng = thread_rng();
let signed_pubkey = unsigned_pubkey.sign(&mut rng, self, || "".into())?;
let signed_pubkey = unsigned_pubkey.sign(
&mut rng,
&self.primary_key,
&*self.primary_key.public_key(),
&Password::empty(),
)?;
Ok(signed_pubkey)
}
}
Expand Down
63 changes: 27 additions & 36 deletions src/pgp.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp).

use std::collections::{BTreeMap, HashSet};
use std::io;
use std::io::Cursor;
use std::io::{BufRead, Cursor};

use anyhow::{bail, Context as _, Result};
use deltachat_contact_tools::EmailAddress;
Expand All @@ -14,8 +13,11 @@ use pgp::composed::{
use pgp::crypto::ecc_curve::ECCCurve;
use pgp::crypto::hash::HashAlgorithm;
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::types::{CompressionAlgorithm, PublicKeyTrait, SignatureBytes, StringToKey};
use rand::{thread_rng, CryptoRng, Rng};
use pgp::types::{
CompressionAlgorithm, KeyDetails, Password, PublicKeyTrait, SignatureBytes, StringToKey,
};
use pgp::TheRing;
use rand::thread_rng;
use tokio::runtime::Handle;

use crate::key::{DcKey, Fingerprint};
Expand All @@ -29,7 +31,7 @@ pub const HEADER_SETUPCODE: &str = "passphrase-begin";
const SYMMETRIC_KEY_ALGORITHM: SymmetricKeyAlgorithm = SymmetricKeyAlgorithm::AES128;

/// Preferred cryptographic hash.
const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::SHA2_256;
const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha256;

/// A wrapper for rPGP public key types
#[derive(Debug)]
Expand All @@ -38,7 +40,7 @@ enum SignedPublicKeyOrSubkey<'a> {
Subkey(&'a SignedPublicSubKey),
}

impl PublicKeyTrait for SignedPublicKeyOrSubkey<'_> {
impl KeyDetails for SignedPublicKeyOrSubkey<'_> {
fn version(&self) -> pgp::types::KeyVersion {
match self {
Self::Key(k) => k.version(),
Expand Down Expand Up @@ -66,7 +68,9 @@ impl PublicKeyTrait for SignedPublicKeyOrSubkey<'_> {
Self::Subkey(k) => k.algorithm(),
}
}
}

impl PublicKeyTrait for SignedPublicKeyOrSubkey<'_> {
fn created_at(&self) -> &chrono::DateTime<chrono::Utc> {
match self {
Self::Key(k) => k.created_at(),
Expand All @@ -93,25 +97,6 @@ impl PublicKeyTrait for SignedPublicKeyOrSubkey<'_> {
}
}

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

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

fn public_params(&self) -> &pgp::types::PublicParams {
match self {
Self::Key(k) => k.public_params(),
Expand Down Expand Up @@ -197,11 +182,10 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
SymmetricKeyAlgorithm::AES128,
])
.preferred_hash_algorithms(smallvec![
HashAlgorithm::SHA2_256,
HashAlgorithm::SHA2_384,
HashAlgorithm::SHA2_512,
HashAlgorithm::SHA2_224,
HashAlgorithm::SHA1,
HashAlgorithm::Sha256,
HashAlgorithm::Sha384,
HashAlgorithm::Sha512,
HashAlgorithm::Sha224,
])
.preferred_compression_algorithms(smallvec![
CompressionAlgorithm::ZLIB,
Expand All @@ -222,7 +206,7 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
let secret_key = key_params
.generate(&mut rng)
.context("failed to generate the key")?
.sign(&mut rng, || "".into())
.sign(&mut rng, &Password::empty())
.context("failed to sign secret key")?;
secret_key
.verify()
Expand Down Expand Up @@ -328,11 +312,18 @@ pub fn pk_decrypt(
private_keys_for_decryption: &[SignedSecretKey],
) -> Result<pgp::composed::Message> {
let cursor = Cursor::new(ctext);
let (msg, _headers) = Message::from_armor_single(cursor)?;
let (msg, _headers) = Message::from_armor(cursor)?;

let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.iter().collect();

let (msg, _key_ids) = msg.decrypt(|| "".into(), &skeys[..])?;
let ring = TheRing {
secret_keys: skeys,
key_passwords: vec![],
message_password: vec![],
session_keys: vec![],
allow_legacy: false,
};
let (msg, _key_ids) = msg.decrypt_the_ring(ring, true)?;

// get_content() will decompress the message if needed,
// but this avoids decompressing it again to check signatures
Expand Down Expand Up @@ -404,15 +395,15 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
}

/// Symmetric decryption.
pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
pub async fn symm_decrypt<'a, T: BufRead + std::fmt::Debug + 'a>(
passphrase: &str,
ctext: T,
) -> Result<Vec<u8>> {
let (enc_msg, _) = Message::from_armor_single(ctext)?;
let (enc_msg, _) = Message::from_armor(ctext)?;

let passphrase = passphrase.to_string();
tokio::task::spawn_blocking(move || {
let msg = enc_msg.decrypt_with_password(|| passphrase)?;
let msg = enc_msg.decrypt_with_password(&Password::empty())?;

match msg.get_content()? {
Some(content) => Ok(content),
Expand Down
Loading