build: update to rPGP 0.16.0 (#6719)

Co-authored-by: Heiko Schaefer <heiko@schaefer.name>
Co-authored-by: link2xt <link2xt@testrun.org>
This commit is contained in:
Friedel Ziegelmayer
2025-05-29 15:06:18 +02:00
committed by GitHub
parent 42975b2ff3
commit 5c2af42cdd
12 changed files with 341 additions and 181 deletions

180
Cargo.lock generated
View File

@@ -439,10 +439,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]] [[package]]
name = "bitfield" name = "bitfields"
version = "0.17.0" version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" checksum = "a1d84268bbf9b487d31fe4b849edbefcd3911422d7a07de855a2da1f70ab3d1c"
dependencies = [
"bitfields-impl",
]
[[package]]
name = "bitfields-impl"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07c93edde7bb4416c35c85048e34f78999dcb47d199bde3b1d79286156f3e2fb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
"thiserror 2.0.12",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@@ -456,6 +471,18 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]] [[package]]
name = "blake2" name = "blake2"
version = "0.10.6" version = "0.10.6"
@@ -623,16 +650,6 @@ dependencies = [
"alloc-stdlib", "alloc-stdlib",
] ]
[[package]]
name = "bstr"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "buffer-redux" name = "buffer-redux"
version = "1.0.2" version = "1.0.2"
@@ -1141,7 +1158,7 @@ dependencies = [
"crypto_secretbox", "crypto_secretbox",
"curve25519-dalek", "curve25519-dalek",
"salsa20", "salsa20",
"serdect", "serdect 0.2.0",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
@@ -1200,6 +1217,23 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "cx448"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c0cf476284b03eb6c10e78787b21c7abb7d7d43cb2f02532ba6b831ed892fa"
dependencies = [
"crypto-bigint",
"elliptic-curve",
"pkcs8",
"rand_core 0.6.4",
"serdect 0.3.0",
"sha3",
"signature",
"subtle",
"zeroize",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.10" version = "0.20.10"
@@ -1526,7 +1560,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
dependencies = [ dependencies = [
"derive_more-impl", "derive_more-impl 1.0.0",
]
[[package]]
name = "derive_more"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
dependencies = [
"derive_more-impl 2.0.1",
] ]
[[package]] [[package]]
@@ -1541,6 +1584,18 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "derive_more-impl"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
"unicode-xid",
]
[[package]] [[package]]
name = "des" name = "des"
version = "0.8.1" version = "0.8.1"
@@ -1735,6 +1790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [ dependencies = [
"base16ct", "base16ct",
"base64ct",
"crypto-bigint", "crypto-bigint",
"digest", "digest",
"ff", "ff",
@@ -1745,7 +1801,10 @@ dependencies = [
"pkcs8", "pkcs8",
"rand_core 0.6.4", "rand_core 0.6.4",
"sec1", "sec1",
"serde_json",
"serdect 0.2.0",
"subtle", "subtle",
"tap",
"zeroize", "zeroize",
] ]
@@ -1930,6 +1989,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
dependencies = [ dependencies = [
"bitvec",
"rand_core 0.6.4", "rand_core 0.6.4",
"subtle", "subtle",
] ]
@@ -1965,6 +2025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"libz-rs-sys",
"miniz_oxide", "miniz_oxide",
] ]
@@ -2002,6 +2063,12 @@ dependencies = [
name = "format-flowed" name = "format-flowed"
version = "1.0.0" version = "1.0.0"
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.31" version = "0.3.31"
@@ -2867,7 +2934,7 @@ dependencies = [
"crypto_box", "crypto_box",
"data-encoding", "data-encoding",
"der", "der",
"derive_more", "derive_more 1.0.0",
"ed25519-dalek", "ed25519-dalek",
"futures-buffered", "futures-buffered",
"futures-util", "futures-util",
@@ -2921,7 +2988,7 @@ checksum = "f91ac4aaab68153d726c4e6b39c30f9f9253743f0e25664e52f4caeb46f48d11"
dependencies = [ dependencies = [
"curve25519-dalek", "curve25519-dalek",
"data-encoding", "data-encoding",
"derive_more", "derive_more 1.0.0",
"ed25519-dalek", "ed25519-dalek",
"rand_core 0.6.4", "rand_core 0.6.4",
"serde", "serde",
@@ -2951,7 +3018,7 @@ dependencies = [
"anyhow", "anyhow",
"async-channel 2.3.1", "async-channel 2.3.1",
"bytes", "bytes",
"derive_more", "derive_more 1.0.0",
"ed25519-dalek", "ed25519-dalek",
"futures-concurrency", "futures-concurrency",
"futures-lite", "futures-lite",
@@ -3062,7 +3129,7 @@ dependencies = [
"bytes", "bytes",
"cfg_aliases", "cfg_aliases",
"data-encoding", "data-encoding",
"derive_more", "derive_more 1.0.0",
"getrandom 0.3.3", "getrandom 0.3.3",
"hickory-resolver", "hickory-resolver",
"http 1.1.0", "http 1.1.0",
@@ -3110,12 +3177,6 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "iter-read"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@@ -3216,6 +3277,15 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "libz-rs-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a"
dependencies = [
"zlib-rs",
]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.14" version = "0.4.14"
@@ -3416,7 +3486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794"
dependencies = [ dependencies = [
"cfg_aliases", "cfg_aliases",
"derive_more", "derive_more 1.0.0",
"futures-buffered", "futures-buffered",
"futures-lite", "futures-lite",
"futures-util", "futures-util",
@@ -3564,7 +3634,7 @@ dependencies = [
"atomic-waker", "atomic-waker",
"bytes", "bytes",
"cfg_aliases", "cfg_aliases",
"derive_more", "derive_more 1.0.0",
"iroh-quinn-udp", "iroh-quinn-udp",
"js-sys", "js-sys",
"libc", "libc",
@@ -4059,21 +4129,22 @@ dependencies = [
[[package]] [[package]]
name = "pgp" name = "pgp"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30249ac8a98b356b473b04bc5358c75a260aa96a295d0743ce752fe7b173f235" checksum = "f91d320242d9b686612b15526fe38711afdf856e112eaa4775ce25b0d9b12b11"
dependencies = [ dependencies = [
"aead",
"aes", "aes",
"aes-gcm", "aes-gcm",
"aes-kw", "aes-kw",
"argon2", "argon2",
"base64", "base64",
"bitfield", "bitfields",
"block-padding", "block-padding",
"blowfish", "blowfish",
"bstr",
"buffer-redux", "buffer-redux",
"byteorder", "byteorder",
"bytes",
"camellia", "camellia",
"cast5", "cast5",
"cfb-mode", "cfb-mode",
@@ -4082,8 +4153,9 @@ dependencies = [
"const-oid", "const-oid",
"crc24", "crc24",
"curve25519-dalek", "curve25519-dalek",
"cx448",
"derive_builder", "derive_builder",
"derive_more", "derive_more 2.0.1",
"des", "des",
"digest", "digest",
"dsa", "dsa",
@@ -4096,7 +4168,6 @@ dependencies = [
"hex", "hex",
"hkdf", "hkdf",
"idea", "idea",
"iter-read",
"k256", "k256",
"log", "log",
"md-5", "md-5",
@@ -4109,6 +4180,7 @@ dependencies = [
"p384", "p384",
"p521", "p521",
"rand 0.8.5", "rand 0.8.5",
"regex",
"ripemd", "ripemd",
"rsa", "rsa",
"sha1", "sha1",
@@ -4117,7 +4189,7 @@ dependencies = [
"sha3", "sha3",
"signature", "signature",
"smallvec", "smallvec",
"thiserror 2.0.12", "snafu",
"twofish", "twofish",
"x25519-dalek", "x25519-dalek",
"zeroize", "zeroize",
@@ -4343,7 +4415,7 @@ checksum = "7d6db66007eac4a0ec8331d0d20c734bd64f6445d64bbaf0d0a27fea7a054e36"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
"derive_more", "derive_more 1.0.0",
"futures-lite", "futures-lite",
"futures-util", "futures-util",
"hyper-util", "hyper-util",
@@ -4640,6 +4712,12 @@ version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]] [[package]]
name = "radix_trie" name = "radix_trie"
version = "0.2.1" version = "0.2.1"
@@ -5198,6 +5276,7 @@ dependencies = [
"der", "der",
"generic-array", "generic-array",
"pkcs8", "pkcs8",
"serdect 0.2.0",
"subtle", "subtle",
"zeroize", "zeroize",
] ]
@@ -5339,6 +5418,16 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serdect"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f42f67da2385b51a5f9652db9c93d78aeaf7610bf5ec366080b6de810604af53"
dependencies = [
"base16ct",
"serde",
]
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.10.1" version = "0.10.1"
@@ -5786,6 +5875,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.19.1" version = "3.19.1"
@@ -7051,6 +7146,15 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]] [[package]]
name = "x25519-dalek" name = "x25519-dalek"
version = "2.0.1" version = "2.0.1"
@@ -7288,6 +7392,12 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "zlib-rs"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8"
[[package]] [[package]]
name = "zune-core" name = "zune-core"
version = "0.4.12" version = "0.4.12"

View File

@@ -74,7 +74,7 @@ num-derive = "0.4"
num-traits = { workspace = true } num-traits = { workspace = true }
parking_lot = "0.12" parking_lot = "0.12"
percent-encoding = "2.3" percent-encoding = "2.3"
pgp = { version = "0.15.0", default-features = false } pgp = { version = "0.16.0", default-features = false }
pin-project = "1" pin-project = "1"
qrcodegen = "1.7.0" qrcodegen = "1.7.0"
quick-xml = "0.37" quick-xml = "0.37"

View File

@@ -22,6 +22,8 @@ ignore = [
skip = [ skip = [
{ name = "async-channel", version = "1.9.0" }, { name = "async-channel", version = "1.9.0" },
{ name = "bitflags", version = "1.3.2" }, { name = "bitflags", version = "1.3.2" },
{ name = "derive_more-impl", version = "1.0.0" },
{ name = "derive_more", version = "1.0.0" },
{ name = "event-listener", version = "2.5.3" }, { name = "event-listener", version = "2.5.3" },
{ name = "generator", version = "0.7.5" }, { name = "generator", version = "0.7.5" },
{ name = "getrandom", version = "0.2.12" }, { name = "getrandom", version = "0.2.12" },
@@ -38,6 +40,7 @@ skip = [
{ name = "regex-automata", version = "0.1.10" }, { name = "regex-automata", version = "0.1.10" },
{ name = "regex-syntax", version = "0.6.29" }, { name = "regex-syntax", version = "0.6.29" },
{ name = "rustix", version = "0.38.44" }, { name = "rustix", version = "0.38.44" },
{ name = "serdect", version = "0.2.0" },
{ name = "spin", version = "0.9.8" }, { name = "spin", version = "0.9.8" },
{ name = "strum_macros", version = "0.26.2" }, { name = "strum_macros", version = "0.26.2" },
{ name = "strum", version = "0.26.2" }, { name = "strum", version = "0.26.2" },

View File

@@ -10,8 +10,8 @@ use std::time::Duration;
use anyhow::{bail, ensure, Context as _, Result}; use anyhow::{bail, ensure, Context as _, Result};
use async_channel::{self as channel, Receiver, Sender}; use async_channel::{self as channel, Receiver, Sender};
use pgp::composed::SignedPublicKey;
use pgp::types::PublicKeyTrait; use pgp::types::PublicKeyTrait;
use pgp::SignedPublicKey;
use ratelimit::Ratelimit; use ratelimit::Ratelimit;
use tokio::sync::{Mutex, Notify, RwLock}; use tokio::sync::{Mutex, Notify, RwLock};
@@ -1074,7 +1074,7 @@ impl Context {
res += &format!("db_size_bytes {db_size}\n"); res += &format!("db_size_bytes {db_size}\n");
let secret_key = &load_self_secret_key(self).await?.primary_key; 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 {key_created}\n"); res += &format!("key_created {key_created}\n");
// how many of the chats active in the last months are: // how many of the chats active in the last months are:

View File

@@ -15,10 +15,10 @@ use crate::pgp;
/// Tries to decrypt a message, but only if it is structured as an Autocrypt message. /// 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. /// If successful and the message is encrypted, returns decrypted body.
pub fn try_decrypt( pub fn try_decrypt<'a>(
mail: &ParsedMail<'_>, mail: &'a ParsedMail<'a>,
private_keyring: &[SignedSecretKey], private_keyring: &'a [SignedSecretKey],
) -> Result<Option<::pgp::composed::Message>> { ) -> Result<Option<::pgp::composed::Message<'static>>> {
let Some(encrypted_data_part) = get_encrypted_mime(mail) else { let Some(encrypted_data_part) = get_encrypted_mime(mail) else {
return Ok(None); return Ok(None);
}; };

View File

@@ -143,7 +143,7 @@ impl EncryptHelper {
let cursor = Cursor::new(&mut raw_message); let cursor = Cursor::new(&mut raw_message);
mail_to_encrypt.clone().write_part(cursor).ok(); mail_to_encrypt.clone().write_part(cursor).ok();
let ctext = pgp::pk_encrypt(&raw_message, keyring, Some(sign_key), compress).await?; let ctext = pgp::pk_encrypt(raw_message, keyring, Some(sign_key), compress).await?;
Ok(ctext) Ok(ctext)
} }
@@ -153,9 +153,8 @@ impl EncryptHelper {
pub async fn sign(self, context: &Context, mail: &MimePart<'static>) -> Result<String> { pub async fn sign(self, context: &Context, mail: &MimePart<'static>) -> Result<String> {
let sign_key = load_self_secret_key(context).await?; let sign_key = load_self_secret_key(context).await?;
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let cursor = Cursor::new(&mut buffer); mail.clone().write_part(&mut buffer)?;
mail.clone().write_part(cursor).ok(); let signature = pgp::pk_calc_signature(buffer, &sign_key)?;
let signature = pgp::pk_calc_signature(&buffer, &sign_key)?;
Ok(signature) Ok(signature)
} }
} }

View File

@@ -4,7 +4,6 @@ use std::ffi::OsStr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin; use std::pin::Pin;
use ::pgp::types::PublicKeyTrait;
use anyhow::{bail, ensure, format_err, Context as _, Result}; use anyhow::{bail, ensure, format_err, Context as _, Result};
use futures::TryStreamExt; use futures::TryStreamExt;
use futures_lite::FutureExt; use futures_lite::FutureExt;
@@ -32,6 +31,7 @@ use crate::tools::{
mod key_transfer; mod key_transfer;
mod transfer; mod transfer;
use ::pgp::types::KeyDetails;
pub use key_transfer::{continue_key_transfer, initiate_key_transfer}; pub use key_transfer::{continue_key_transfer, initiate_key_transfer};
pub use transfer::{get_backup, BackupProvider}; pub use transfer::{get_backup, BackupProvider};
@@ -173,7 +173,11 @@ async fn set_self_key(context: &Context, armored: &str) -> Result<()> {
}; };
key::store_self_keypair(context, &keypair).await?; 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(()) Ok(())
} }

View File

@@ -1,4 +1,6 @@
//! # Key transfer via Autocrypt Setup Message. //! # Key transfer via Autocrypt Setup Message.
use std::io::BufReader;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use anyhow::{bail, ensure, Result}; use anyhow::{bail, ensure, Result};
@@ -71,7 +73,7 @@ pub async fn continue_key_transfer(
if let Some(filename) = msg.get_file(context) { if let Some(filename) = msg.get_file(context) {
let file = open_file_std(context, filename)?; let file = open_file_std(context, filename)?;
let sc = normalize_setup_code(setup_code); let sc = normalize_setup_code(setup_code);
let armored_key = decrypt_setup_file(&sc, file).await?; let armored_key = decrypt_setup_file(&sc, BufReader::new(file)).await?;
set_self_key(context, &armored_key).await?; set_self_key(context, &armored_key).await?;
context.set_config_bool(Config::BccSelf, true).await?; context.set_config_bool(Config::BccSelf, true).await?;
@@ -96,7 +98,7 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<St
true => Some(("Autocrypt-Prefer-Encrypt", "mutual")), true => Some(("Autocrypt-Prefer-Encrypt", "mutual")),
}; };
let private_key_asc = private_key.to_asc(ac_headers); let private_key_asc = private_key.to_asc(ac_headers);
let encr = pgp::symm_encrypt(passphrase, private_key_asc.as_bytes()) let encr = pgp::symm_encrypt(passphrase, private_key_asc.into_bytes())
.await? .await?
.replace('\n', "\r\n"); .replace('\n', "\r\n");
@@ -155,7 +157,7 @@ fn create_setup_code(_context: &Context) -> String {
ret ret
} }
async fn decrypt_setup_file<T: std::io::Read + std::io::Seek>( async fn decrypt_setup_file<T: std::fmt::Debug + std::io::BufRead + Send + 'static>(
passphrase: &str, passphrase: &str,
file: T, file: T,
) -> Result<String> { ) -> Result<String> {
@@ -258,11 +260,10 @@ mod tests {
assert!(!base64.is_empty()); assert!(!base64.is_empty());
let setup_file = S_EM_SETUPFILE.to_string(); let setup_file = S_EM_SETUPFILE;
let decrypted = let decrypted = decrypt_setup_file(S_EM_SETUPCODE, setup_file.as_bytes())
decrypt_setup_file(S_EM_SETUPCODE, std::io::Cursor::new(setup_file.as_bytes())) .await
.await .unwrap();
.unwrap();
let (typ, headers, _base64) = split_armored_data(decrypted.as_bytes()).unwrap(); let (typ, headers, _base64) = split_armored_data(decrypted.as_bytes()).unwrap();
@@ -278,14 +279,13 @@ mod tests {
/// "Implementations MUST NOT use plaintext in Symmetrically Encrypted Data packets". /// "Implementations MUST NOT use plaintext in Symmetrically Encrypted Data packets".
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_plaintext_autocrypt_setup_message() { async fn test_decrypt_plaintext_autocrypt_setup_message() {
let setup_file = S_PLAINTEXT_SETUPFILE.to_string(); let setup_file = S_PLAINTEXT_SETUPFILE;
let incorrect_setupcode = "0000-0000-0000-0000-0000-0000-0000-0000-0000"; let incorrect_setupcode = "0000-0000-0000-0000-0000-0000-0000-0000-0000";
assert!(decrypt_setup_file( assert!(
incorrect_setupcode, decrypt_setup_file(incorrect_setupcode, setup_file.as_bytes(),)
std::io::Cursor::new(setup_file.as_bytes()), .await
) .is_err()
.await );
.is_err());
} }
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]

View File

@@ -10,7 +10,7 @@ use deltachat_contact_tools::EmailAddress;
use pgp::composed::Deserializable; use pgp::composed::Deserializable;
pub use pgp::composed::{SignedPublicKey, SignedSecretKey}; pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
use pgp::ser::Serialize; use pgp::ser::Serialize;
use pgp::types::{PublicKeyTrait, SecretKeyTrait}; use pgp::types::{KeyDetails, KeyId, Password};
use rand::thread_rng; use rand::thread_rng;
use tokio::runtime::Handle; use tokio::runtime::Handle;
@@ -24,7 +24,7 @@ use crate::tools::{self, time_elapsed};
/// This trait is implemented for rPGP's [SignedPublicKey] and /// This trait is implemented for rPGP's [SignedPublicKey] and
/// [SignedSecretKey] types and makes working with them a little /// [SignedSecretKey] types and makes working with them a little
/// easier in the deltachat world. /// easier in the deltachat world.
pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone { pub(crate) trait DcKey: Serialize + Deserializable + Clone {
/// Create a key from some bytes. /// Create a key from some bytes.
fn from_slice(bytes: &[u8]) -> Result<Self> { fn from_slice(bytes: &[u8]) -> Result<Self> {
let res = <Self as Deserializable>::from_bytes(Cursor::new(bytes)); let res = <Self as Deserializable>::from_bytes(Cursor::new(bytes));
@@ -78,7 +78,7 @@ pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone {
let bytes = data.as_bytes(); let bytes = data.as_bytes();
let res = Self::from_armor_single(Cursor::new(bytes)); let res = Self::from_armor_single(Cursor::new(bytes));
let (key, headers) = match res { 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"), true => bail!("No private key packet found"),
false => bail!("No public key packet found"), false => bail!("No public key packet found"),
}, },
@@ -123,11 +123,10 @@ pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone {
fn to_asc(&self, header: Option<(&str, &str)>) -> String; fn to_asc(&self, header: Option<(&str, &str)>) -> String;
/// The fingerprint for the key. /// The fingerprint for the key.
fn dc_fingerprint(&self) -> Fingerprint { fn dc_fingerprint(&self) -> Fingerprint;
PublicKeyTrait::fingerprint(self).into()
}
fn is_private() -> bool; fn is_private() -> bool;
fn key_id(&self) -> KeyId;
} }
pub(crate) async fn load_self_public_key(context: &Context) -> Result<SignedPublicKey> { pub(crate) async fn load_self_public_key(context: &Context) -> Result<SignedPublicKey> {
@@ -230,6 +229,14 @@ impl DcKey for SignedPublicKey {
fn is_private() -> bool { fn is_private() -> bool {
false false
} }
fn dc_fingerprint(&self) -> Fingerprint {
self.fingerprint().into()
}
fn key_id(&self) -> KeyId {
KeyDetails::key_id(self)
}
} }
impl DcKey for SignedSecretKey { impl DcKey for SignedSecretKey {
@@ -249,6 +256,14 @@ impl DcKey for SignedSecretKey {
fn is_private() -> bool { fn is_private() -> bool {
true true
} }
fn dc_fingerprint(&self) -> Fingerprint {
self.fingerprint().into()
}
fn key_id(&self) -> KeyId {
KeyDetails::key_id(&**self)
}
} }
/// Deltachat extension trait for secret keys. /// Deltachat extension trait for secret keys.
@@ -262,9 +277,14 @@ pub(crate) trait DcSecretKey {
impl DcSecretKey for SignedSecretKey { impl DcSecretKey for SignedSecretKey {
fn split_public_key(&self) -> Result<SignedPublicKey> { fn split_public_key(&self) -> Result<SignedPublicKey> {
self.verify()?; self.verify()?;
let unsigned_pubkey = SecretKeyTrait::public_key(self); let unsigned_pubkey = self.public_key();
let mut rng = thread_rng(); 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) Ok(signed_pubkey)
} }
} }

View File

@@ -342,10 +342,10 @@ impl MimeMessage {
let mail_raw; // Memory location for a possible decrypted message. let mail_raw; // Memory location for a possible decrypted message.
let decrypted_msg; // Decrypted signed OpenPGP message. let decrypted_msg; // Decrypted signed OpenPGP message.
let (mail, encrypted) = let (mail, is_encrypted) =
match tokio::task::block_in_place(|| try_decrypt(&mail, &private_keyring)) { match tokio::task::block_in_place(|| try_decrypt(&mail, &private_keyring)) {
Ok(Some(msg)) => { Ok(Some(mut msg)) => {
mail_raw = msg.get_content()?.unwrap_or_default(); mail_raw = msg.as_data_vec().unwrap_or_default();
let decrypted_mail = mailparse::parse_mail(&mail_raw)?; let decrypted_mail = mailparse::parse_mail(&mail_raw)?;
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() { if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
@@ -434,7 +434,7 @@ impl MimeMessage {
signatures.extend(signatures_detached); signatures.extend(signatures_detached);
content content
}); });
if let (Ok(mail), true) = (mail, encrypted) { if let (Ok(mail), true) = (mail, is_encrypted) {
if !signatures.is_empty() { if !signatures.is_empty() {
// Remove unsigned opportunistically protected headers from messages considered // Remove unsigned opportunistically protected headers from messages considered
// Autocrypt-encrypted / displayed with padlock. // Autocrypt-encrypted / displayed with padlock.
@@ -529,7 +529,7 @@ impl MimeMessage {
} }
} }
} }
if !encrypted { if !is_encrypted {
signatures.clear(); signatures.clear();
} }
if let Some(peerstate) = &mut peerstate { if let Some(peerstate) = &mut peerstate {

View File

@@ -1,19 +1,22 @@
//! 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::io::Cursor; use std::io::{BufRead, Cursor};
use anyhow::{bail, Context as _, Result}; use anyhow::{Context as _, Result};
use chrono::SubsecRound;
use deltachat_contact_tools::EmailAddress; use deltachat_contact_tools::EmailAddress;
use pgp::armor::BlockType; use pgp::armor::BlockType;
use pgp::composed::{ use pgp::composed::{
Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey, ArmorOptions, Deserializable, KeyType as PgpKeyType, Message, MessageBuilder,
SignedPublicSubKey, SignedSecretKey, StandaloneSignature, SubkeyParamsBuilder, SecretKeyParamsBuilder, SignedPublicKey, SignedPublicSubKey, SignedSecretKey,
StandaloneSignature, SubkeyParamsBuilder, TheRing,
}; };
use pgp::crypto::ecc_curve::ECCCurve; use pgp::crypto::ecc_curve::ECCCurve;
use pgp::crypto::hash::HashAlgorithm; use pgp::crypto::hash::HashAlgorithm;
use pgp::crypto::sym::SymmetricKeyAlgorithm; use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::types::{CompressionAlgorithm, PublicKeyTrait, StringToKey}; use pgp::packet::{SignatureConfig, SignatureType, Subpacket, SubpacketData};
use pgp::types::{CompressionAlgorithm, KeyDetails, Password, PublicKeyTrait, StringToKey};
use rand::thread_rng; use rand::thread_rng;
use tokio::runtime::Handle; use tokio::runtime::Handle;
@@ -28,7 +31,7 @@ pub const HEADER_SETUPCODE: &str = "passphrase-begin";
const SYMMETRIC_KEY_ALGORITHM: SymmetricKeyAlgorithm = SymmetricKeyAlgorithm::AES128; const SYMMETRIC_KEY_ALGORITHM: SymmetricKeyAlgorithm = SymmetricKeyAlgorithm::AES128;
/// Preferred cryptographic hash. /// Preferred cryptographic hash.
const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::SHA2_256; const HASH_ALGORITHM: HashAlgorithm = HashAlgorithm::Sha256;
/// Split data from PGP Armored Data as defined in <https://tools.ietf.org/html/rfc4880#section-6.2>. /// Split data from PGP Armored Data as defined in <https://tools.ietf.org/html/rfc4880#section-6.2>.
/// ///
@@ -91,7 +94,7 @@ impl KeyPair {
/// Both secret and public key consist of signing primary key and encryption subkey /// Both secret and public key consist of signing primary key and encryption subkey
/// as [described in the Autocrypt standard](https://autocrypt.org/level1.html#openpgp-based-key-data). /// as [described in the Autocrypt standard](https://autocrypt.org/level1.html#openpgp-based-key-data).
pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> { pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
let signing_key_type = PgpKeyType::EdDSALegacy; let signing_key_type = PgpKeyType::Ed25519Legacy;
let encryption_key_type = PgpKeyType::ECDH(ECCCurve::Curve25519); let encryption_key_type = PgpKeyType::ECDH(ECCCurve::Curve25519);
let user_id = format!("<{addr}>"); let user_id = format!("<{addr}>");
@@ -107,11 +110,10 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
SymmetricKeyAlgorithm::AES128, SymmetricKeyAlgorithm::AES128,
]) ])
.preferred_hash_algorithms(smallvec![ .preferred_hash_algorithms(smallvec![
HashAlgorithm::SHA2_256, HashAlgorithm::Sha256,
HashAlgorithm::SHA2_384, HashAlgorithm::Sha384,
HashAlgorithm::SHA2_512, HashAlgorithm::Sha512,
HashAlgorithm::SHA2_224, HashAlgorithm::Sha224,
HashAlgorithm::SHA1,
]) ])
.preferred_compression_algorithms(smallvec![ .preferred_compression_algorithms(smallvec![
CompressionAlgorithm::ZLIB, CompressionAlgorithm::ZLIB,
@@ -132,7 +134,7 @@ pub(crate) fn create_keypair(addr: EmailAddress) -> Result<KeyPair> {
let secret_key = key_params let secret_key = key_params
.generate(&mut rng) .generate(&mut rng)
.context("failed to generate the key")? .context("failed to generate the key")?
.sign(&mut rng, || "".into()) .sign(&mut rng, &Password::empty())
.context("failed to sign secret key")?; .context("failed to sign secret key")?;
secret_key secret_key
.verify() .verify()
@@ -160,55 +162,73 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<&SignedPublicSubKey
/// Encrypts `plain` text using `public_keys_for_encryption` /// Encrypts `plain` text using `public_keys_for_encryption`
/// and signs it using `private_key_for_signing`. /// and signs it using `private_key_for_signing`.
pub async fn pk_encrypt( pub async fn pk_encrypt(
plain: &[u8], plain: Vec<u8>,
public_keys_for_encryption: Vec<SignedPublicKey>, public_keys_for_encryption: Vec<SignedPublicKey>,
private_key_for_signing: Option<SignedSecretKey>, private_key_for_signing: Option<SignedSecretKey>,
compress: bool, compress: bool,
) -> Result<String> { ) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain);
Handle::current() Handle::current()
.spawn_blocking(move || { .spawn_blocking(move || {
let pkeys: Vec<&SignedPublicSubKey> = public_keys_for_encryption
.iter()
.filter_map(select_pk_for_encryption)
.collect();
let mut rng = thread_rng(); let mut rng = thread_rng();
let encrypted_msg = if let Some(ref skey) = private_key_for_signing { let pkeys = public_keys_for_encryption
let signed_msg = lit_msg.sign(&mut rng, skey, || "".into(), HASH_ALGORITHM)?; .iter()
let compressed_msg = if compress { .filter_map(select_pk_for_encryption);
signed_msg.compress(CompressionAlgorithm::ZLIB)?
} else {
signed_msg
};
compressed_msg.encrypt_to_keys_seipdv1(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys)?
} else {
lit_msg.encrypt_to_keys_seipdv1(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys)?
};
let encoded_msg = encrypted_msg.to_armored_string(Default::default())?; let msg = MessageBuilder::from_bytes("", plain);
let mut msg = msg.seipd_v1(&mut rng, SYMMETRIC_KEY_ALGORITHM);
for pkey in pkeys {
msg.encrypt_to_key(&mut rng, &pkey)?;
}
if let Some(ref skey) = private_key_for_signing {
msg.sign(&**skey, Password::empty(), HASH_ALGORITHM);
if compress {
msg.compression(CompressionAlgorithm::ZLIB);
}
}
let encoded_msg = msg.to_armored_string(&mut rng, Default::default())?;
Ok(encoded_msg) Ok(encoded_msg)
}) })
.await? .await?
} }
/// Signs `plain` text using `private_key_for_signing`. /// Produces a detached signature for `plain` text using `private_key_for_signing`.
pub fn pk_calc_signature( pub fn pk_calc_signature(
plain: &[u8], plain: Vec<u8>,
private_key_for_signing: &SignedSecretKey, private_key_for_signing: &SignedSecretKey,
) -> Result<String> { ) -> Result<String> {
let mut rng = thread_rng(); let rng = thread_rng();
let msg = Message::new_literal_bytes("", plain).sign(
&mut rng, let mut config = SignatureConfig::from_key(
private_key_for_signing, rng,
|| "".into(), &private_key_for_signing.primary_key,
HASH_ALGORITHM, SignatureType::Binary,
)?; )?;
let signature = msg.into_signature().to_armored_string(Default::default())?;
Ok(signature) config.hashed_subpackets = vec![
Subpacket::regular(SubpacketData::IssuerFingerprint(
private_key_for_signing.fingerprint(),
))?,
Subpacket::critical(SubpacketData::SignatureCreationTime(
chrono::Utc::now().trunc_subsecs(0),
))?,
];
config.unhashed_subpackets = vec![Subpacket::regular(SubpacketData::Issuer(
private_key_for_signing.key_id(),
))?];
let signature = config.sign(
&private_key_for_signing.primary_key,
&Password::empty(),
plain.as_slice(),
)?;
let sig = StandaloneSignature::new(signature);
Ok(sig.to_armored_string(ArmorOptions::default())?)
} }
/// Decrypts the message with keys from the private key keyring. /// Decrypts the message with keys from the private key keyring.
@@ -218,16 +238,27 @@ pub fn pk_calc_signature(
pub fn pk_decrypt( pub fn pk_decrypt(
ctext: Vec<u8>, ctext: Vec<u8>,
private_keys_for_decryption: &[SignedSecretKey], private_keys_for_decryption: &[SignedSecretKey],
) -> Result<pgp::composed::Message> { ) -> Result<pgp::composed::Message<'static>> {
let cursor = Cursor::new(ctext); 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 skeys: Vec<&SignedSecretKey> = private_keys_for_decryption.iter().collect();
let empty_pw = Password::empty();
let (msg, _key_ids) = msg.decrypt(|| "".into(), &skeys[..])?; let ring = TheRing {
secret_keys: skeys,
key_passwords: vec![&empty_pw],
message_password: vec![],
session_keys: vec![],
allow_legacy: false,
};
let (msg, ring_result) = msg.decrypt_the_ring(ring, true)?;
anyhow::ensure!(
!ring_result.secret_keys.is_empty(),
"decryption failed, no matching secret keys"
);
// get_content() will decompress the message if needed, // remove one layer of compression
// but this avoids decompressing it again to check signatures
let msg = msg.decompress()?; let msg = msg.decompress()?;
Ok(msg) Ok(msg)
@@ -243,9 +274,9 @@ pub fn valid_signature_fingerprints(
public_keys_for_validation: &[SignedPublicKey], public_keys_for_validation: &[SignedPublicKey],
) -> Result<HashSet<Fingerprint>> { ) -> Result<HashSet<Fingerprint>> {
let mut ret_signature_fingerprints: HashSet<Fingerprint> = Default::default(); let mut ret_signature_fingerprints: HashSet<Fingerprint> = Default::default();
if let signed_msg @ pgp::composed::Message::Signed { .. } = msg { if msg.is_signed() {
for pkey in public_keys_for_validation { for pkey in public_keys_for_validation {
if signed_msg.verify(&pkey.primary_key).is_ok() { if msg.verify(&pkey.primary_key).is_ok() {
let fp = pkey.dc_fingerprint(); let fp = pkey.dc_fingerprint();
ret_signature_fingerprints.insert(fp); ret_signature_fingerprints.insert(fp);
} }
@@ -274,21 +305,17 @@ pub fn pk_validate(
} }
/// Symmetric encryption. /// Symmetric encryption.
pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> { pub async fn symm_encrypt(passphrase: &str, plain: Vec<u8>) -> Result<String> {
let lit_msg = Message::new_literal_bytes("", plain); let passphrase = Password::from(passphrase.to_string());
let passphrase = passphrase.to_string();
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let mut rng = thread_rng(); let mut rng = thread_rng();
let s2k = StringToKey::new_default(&mut rng); let s2k = StringToKey::new_default(&mut rng);
let msg = lit_msg.encrypt_with_password_seipdv1( let builder = MessageBuilder::from_bytes("", plain);
&mut rng, let mut builder = builder.seipd_v1(&mut rng, SYMMETRIC_KEY_ALGORITHM);
s2k, builder.encrypt_with_password(s2k, &passphrase)?;
SYMMETRIC_KEY_ALGORITHM,
|| passphrase,
)?;
let encoded_msg = msg.to_armored_string(Default::default())?; let encoded_msg = builder.to_armored_string(&mut rng, Default::default())?;
Ok(encoded_msg) Ok(encoded_msg)
}) })
@@ -296,20 +323,18 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
} }
/// Symmetric decryption. /// Symmetric decryption.
pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>( pub async fn symm_decrypt<T: BufRead + std::fmt::Debug + 'static + Send>(
passphrase: &str, passphrase: &str,
ctext: T, ctext: T,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
let (enc_msg, _) = Message::from_armor_single(ctext)?;
let passphrase = passphrase.to_string(); let passphrase = passphrase.to_string();
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let msg = enc_msg.decrypt_with_password(|| passphrase)?; let (enc_msg, _) = Message::from_armor(ctext)?;
let password = Password::from(passphrase);
match msg.get_content()? { let msg = enc_msg.decrypt_with_password(&password)?;
Some(content) => Ok(content), let res = msg.decompress()?.as_data_vec()?;
None => bail!("Decrypted message is empty"), Ok(res)
}
}) })
.await? .await?
} }
@@ -322,16 +347,21 @@ mod tests {
use super::*; use super::*;
use crate::test_utils::{alice_keypair, bob_keypair}; use crate::test_utils::{alice_keypair, bob_keypair};
fn pk_decrypt_and_validate( fn pk_decrypt_and_validate<'a>(
ctext: Vec<u8>, ctext: &'a [u8],
private_keys_for_decryption: &[SignedSecretKey], private_keys_for_decryption: &'a [SignedSecretKey],
public_keys_for_validation: &[SignedPublicKey], public_keys_for_validation: &[SignedPublicKey],
) -> Result<(pgp::composed::Message, HashSet<Fingerprint>)> { ) -> Result<(
let msg = pk_decrypt(ctext, private_keys_for_decryption)?; pgp::composed::Message<'static>,
HashSet<Fingerprint>,
Vec<u8>,
)> {
let mut msg = pk_decrypt(ctext.to_vec(), private_keys_for_decryption)?;
let content = msg.as_data_vec()?;
let ret_signature_fingerprints = let ret_signature_fingerprints =
valid_signature_fingerprints(&msg, public_keys_for_validation)?; valid_signature_fingerprints(&msg, public_keys_for_validation)?;
Ok((msg, ret_signature_fingerprints)) Ok((msg, ret_signature_fingerprints, content))
} }
#[test] #[test]
@@ -407,7 +437,7 @@ mod tests {
let compress = true; let compress = true;
pk_encrypt( pk_encrypt(
CLEARTEXT, CLEARTEXT.to_vec(),
keyring, keyring,
Some(KEYS.alice_secret.clone()), Some(KEYS.alice_secret.clone()),
compress, compress,
@@ -425,7 +455,7 @@ mod tests {
let keyring = vec![KEYS.alice_public.clone(), KEYS.bob_public.clone()]; let keyring = vec![KEYS.alice_public.clone(), KEYS.bob_public.clone()];
let compress = true; let compress = true;
pk_encrypt(CLEARTEXT, keyring, None, compress) pk_encrypt(CLEARTEXT.to_vec(), keyring, None, compress)
.await .await
.unwrap() .unwrap()
}) })
@@ -453,35 +483,34 @@ mod tests {
// Check decrypting as Alice // Check decrypting as Alice
let decrypt_keyring = vec![KEYS.alice_secret.clone()]; let decrypt_keyring = vec![KEYS.alice_secret.clone()];
let sig_check_keyring = vec![KEYS.alice_public.clone()]; let sig_check_keyring = vec![KEYS.alice_public.clone()];
let (msg, valid_signatures) = pk_decrypt_and_validate( let (_msg, valid_signatures, content) = pk_decrypt_and_validate(
ctext_signed().await.as_bytes().to_vec(), ctext_signed().await.as_bytes(),
&decrypt_keyring, &decrypt_keyring,
&sig_check_keyring, &sig_check_keyring,
) )
.unwrap(); .unwrap();
assert_eq!(msg.get_content().unwrap().unwrap(), CLEARTEXT); assert_eq!(content, CLEARTEXT);
assert_eq!(valid_signatures.len(), 1); assert_eq!(valid_signatures.len(), 1);
// Check decrypting as Bob // Check decrypting as Bob
let decrypt_keyring = vec![KEYS.bob_secret.clone()]; let decrypt_keyring = vec![KEYS.bob_secret.clone()];
let sig_check_keyring = vec![KEYS.alice_public.clone()]; let sig_check_keyring = vec![KEYS.alice_public.clone()];
let (msg, valid_signatures) = pk_decrypt_and_validate( let (_msg, valid_signatures, content) = pk_decrypt_and_validate(
ctext_signed().await.as_bytes().to_vec(), ctext_signed().await.as_bytes(),
&decrypt_keyring, &decrypt_keyring,
&sig_check_keyring, &sig_check_keyring,
) )
.unwrap(); .unwrap();
assert_eq!(msg.get_content().unwrap().unwrap(), CLEARTEXT); assert_eq!(content, CLEARTEXT);
assert_eq!(valid_signatures.len(), 1); assert_eq!(valid_signatures.len(), 1);
} }
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_no_sig_check() { async fn test_decrypt_no_sig_check() {
let keyring = vec![KEYS.alice_secret.clone()]; let keyring = vec![KEYS.alice_secret.clone()];
let (msg, valid_signatures) = let (_msg, valid_signatures, content) =
pk_decrypt_and_validate(ctext_signed().await.as_bytes().to_vec(), &keyring, &[]) pk_decrypt_and_validate(ctext_signed().await.as_bytes(), &keyring, &[]).unwrap();
.unwrap(); assert_eq!(content, CLEARTEXT);
assert_eq!(msg.get_content().unwrap().unwrap(), CLEARTEXT);
assert_eq!(valid_signatures.len(), 0); assert_eq!(valid_signatures.len(), 0);
} }
@@ -490,26 +519,23 @@ mod tests {
// The validation does not have the public key of the signer. // The validation does not have the public key of the signer.
let decrypt_keyring = vec![KEYS.bob_secret.clone()]; let decrypt_keyring = vec![KEYS.bob_secret.clone()];
let sig_check_keyring = vec![KEYS.bob_public.clone()]; let sig_check_keyring = vec![KEYS.bob_public.clone()];
let (msg, valid_signatures) = pk_decrypt_and_validate( let (_msg, valid_signatures, content) = pk_decrypt_and_validate(
ctext_signed().await.as_bytes().to_vec(), ctext_signed().await.as_bytes(),
&decrypt_keyring, &decrypt_keyring,
&sig_check_keyring, &sig_check_keyring,
) )
.unwrap(); .unwrap();
assert_eq!(msg.get_content().unwrap().unwrap(), CLEARTEXT); assert_eq!(content, CLEARTEXT);
assert_eq!(valid_signatures.len(), 0); assert_eq!(valid_signatures.len(), 0);
} }
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decrypt_unsigned() { async fn test_decrypt_unsigned() {
let decrypt_keyring = vec![KEYS.bob_secret.clone()]; let decrypt_keyring = vec![KEYS.bob_secret.clone()];
let (msg, valid_signatures) = pk_decrypt_and_validate( let (_msg, valid_signatures, content) =
ctext_unsigned().await.as_bytes().to_vec(), pk_decrypt_and_validate(ctext_unsigned().await.as_bytes(), &decrypt_keyring, &[])
&decrypt_keyring, .unwrap();
&[], assert_eq!(content, CLEARTEXT);
)
.unwrap();
assert_eq!(msg.get_content().unwrap().unwrap(), CLEARTEXT);
assert_eq!(valid_signatures.len(), 0); assert_eq!(valid_signatures.len(), 0);
} }
} }

View File

@@ -11,9 +11,8 @@ use std::sync::Arc;
use anyhow::{Context as _, Result}; use anyhow::{Context as _, Result};
use base64::Engine as _; use base64::Engine as _;
use pgp::crypto::aead::AeadAlgorithm; use pgp::crypto::aead::{AeadAlgorithm, ChunkSize};
use pgp::crypto::sym::SymmetricKeyAlgorithm; use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::ser::Serialize;
use rand::thread_rng; use rand::thread_rng;
use tokio::sync::RwLock; use tokio::sync::RwLock;
@@ -81,18 +80,17 @@ pub(crate) fn encrypt_device_token(device_token: &str) -> Result<String> {
.first() .first()
.context("No encryption subkey found")?; .context("No encryption subkey found")?;
let padded_device_token = pad_device_token(device_token); let padded_device_token = pad_device_token(device_token);
let literal_message = pgp::composed::Message::new_literal("", &padded_device_token);
let mut rng = thread_rng(); let mut rng = thread_rng();
let chunk_size = 8;
let encrypted_message = literal_message.encrypt_to_keys_seipdv2( let mut msg = pgp::composed::MessageBuilder::from_bytes("", padded_device_token).seipd_v2(
&mut rng, &mut rng,
SymmetricKeyAlgorithm::AES128, SymmetricKeyAlgorithm::AES128,
AeadAlgorithm::Ocb, AeadAlgorithm::Ocb,
chunk_size, ChunkSize::C8KiB,
&[&encryption_subkey], );
)?; msg.encrypt_to_key(&mut rng, &encryption_subkey)?;
let encoded_message = encrypted_message.to_bytes()?; let encoded_message = msg.to_vec(&mut rng)?;
Ok(format!( Ok(format!(
"openpgp:{}", "openpgp:{}",
base64::engine::general_purpose::STANDARD.encode(encoded_message) base64::engine::general_purpose::STANDARD.encode(encoded_message)