diff --git a/Cargo.lock b/Cargo.lock index cedb1890b..cea15bf70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "circular" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -507,7 +507,7 @@ dependencies = [ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pgp 0.2.2", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -860,6 +860,11 @@ name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "hostname" version = "0.1.5" @@ -1556,8 +1561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pgp" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.2.2" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1570,7 +1574,7 @@ dependencies = [ "cast5 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfb-mode 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "circular 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "circular 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "crc24 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "derive_builder 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1580,7 +1584,7 @@ dependencies = [ "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2887,7 +2891,7 @@ dependencies = [ "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f426e64df1c3de26cbf44593c6ffff5dbfd43bbf9de0d075058558126b3fc73" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" -"checksum circular 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82945ea9ff134eba321833377d0c485f5c6fb4c8e26cfec199174e2970d5385a" +"checksum circular 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea" "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" @@ -2946,6 +2950,7 @@ dependencies = [ "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" "checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" @@ -3019,7 +3024,6 @@ dependencies = [ "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -"checksum pgp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb80b37b7debf9a98dc0caca3ed40ddf1d383691208763d0458df0b91521020f" "checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" diff --git a/Cargo.toml b/Cargo.toml index 8302d1f9c..c13d62aa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ deltachat_derive = { path = "./deltachat_derive" } mmime = { version = "0.1.2", path = "./mmime" } libc = "0.2.51" -pgp = { version = "0.2", default-features = false } +pgp = { path = "../../rpgp/rpgp", default-features = false } hex = "0.3.2" sha2 = "0.8.0" rand = "0.6.5" diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 4e8e6fb91..9513d21fe 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -593,6 +593,25 @@ pub fn dc_read_file>( } } +pub fn dc_open_file>( + context: &Context, + path: P, +) -> Result { + let path_abs = dc_get_abs_path(context, &path); + + match fs::File::open(&path_abs) { + Ok(bytes) => Ok(bytes), + Err(err) => { + warn!( + context, + "Cannot read \"{}\" or file is empty.", + path.as_ref().display() + ); + Err(err.into()) + } + } +} + pub(crate) fn dc_get_next_backup_path( folder: impl AsRef, backup_time: i64, @@ -612,6 +631,26 @@ pub(crate) fn dc_get_next_backup_path( } bail!("could not create backup file, disk full?"); } +pub(crate) fn dc_get_fine_path_filename( + context: &Context, + folder: impl AsRef, + backup_time: i64, +) -> Result { + let folder = PathBuf::from(folder.as_ref()); + let stem = chrono::NaiveDateTime::from_timestamp(backup_time, 0) + .format("delta-chat-%Y-%m-%d") + .to_string(); + + // 64 backup files per day should be enough for everyone + for i in 0..64 { + let mut path = folder.clone(); + path.push(format!("{}-{}.bak", stem, i)); + if !path.exists() { + return Ok(path); + } + } + bail!("could not create backup file, disk full?"); +} pub(crate) fn dc_is_blobdir_path(context: &Context, path: impl AsRef) -> bool { context diff --git a/src/error.rs b/src/error.rs index 0df1e6129..bc2ca1d88 100644 --- a/src/error.rs +++ b/src/error.rs @@ -70,12 +70,6 @@ impl From for Error { } } -impl From for Error { - fn from(err: std::string::FromUtf8Error) -> Error { - Error::FromUtf8(err) - } -} - impl From for Error { fn from(err: image_meta::ImageError) -> Error { Error::Image(err) @@ -94,6 +88,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: std::string::FromUtf8Error) -> Error { + Error::FromUtf8(err) + } +} + #[macro_export] macro_rules! bail { ($e:expr) => { diff --git a/src/imex.rs b/src/imex.rs index 953d18fbd..1e5b2ba4b 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -1,7 +1,5 @@ use core::cmp::{max, min}; -use std::ffi::CString; use std::path::{Path, PathBuf}; -use std::ptr; use num_traits::FromPrimitive; use rand::{thread_rng, Rng}; @@ -241,18 +239,12 @@ pub fn continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str) - ); if let Some(filename) = msg.get_file(context) { - if let Ok(ref mut buf) = dc_read_file(context, filename) { - let sc = normalize_setup_code(setup_code); - if let Ok(armored_key) = decrypt_setup_file(context, sc, buf) { - set_self_key(context, &armored_key, true, true)?; - } else { - bail!("Bad setup code.") - } + let file = dc_open_file(context, filename)?; + let sc = normalize_setup_code(setup_code); + let armored_key = decrypt_setup_file(context, &sc, file)?; + set_self_key(context, &armored_key, true, true)?; - Ok(()) - } else { - bail!("Cannot read Autocrypt Setup Message file."); - } + Ok(()) } else { bail!("Message is no Autocrypt Setup Message."); } @@ -326,53 +318,15 @@ fn set_self_key( Ok(()) } -fn decrypt_setup_file( - _context: &Context, - passphrase: impl AsRef, - filecontent: &mut [u8], +fn decrypt_setup_file( + context: &Context, + passphrase: &str, + file: T, ) -> Result { - let mut fc_headerline = String::default(); - let mut fc_base64: *const libc::c_char = ptr::null(); + let plain_bytes = dc_pgp_symm_decrypt(passphrase, file)?; + let plain_text = std::string::String::from_utf8(plain_bytes)?; - let split_result = unsafe { - dc_split_armored_data( - filecontent.as_mut_ptr().cast(), - &mut fc_headerline, - ptr::null_mut(), - ptr::null_mut(), - &mut fc_base64, - ) - }; - - if !split_result || fc_headerline != "-----BEGIN PGP MESSAGE-----" || fc_base64.is_null() { - bail!("Invalid armored data"); - } - - // convert base64 to binary - let base64_encoded = - unsafe { std::slice::from_raw_parts(fc_base64 as *const u8, libc::strlen(fc_base64)) }; - - let data = base64_decode(&base64_encoded)?; - - // decrypt symmetrically - let payload = dc_pgp_symm_decrypt(passphrase.as_ref(), &data)?; - let payload_str = String::from_utf8(payload)?; - - Ok(payload_str) -} - -/// Decode the base64 encoded slice. Handles line breaks. -fn base64_decode(input: &[u8]) -> Result> { - use std::io::Read; - let c = std::io::Cursor::new(input); - let lr = pgp::line_reader::LineReader::new(c); - let br = pgp::base64_reader::Base64Reader::new(lr); - let mut reader = pgp::base64_decoder::Base64Decoder::new(br); - - let mut data = Vec::new(); - reader.read_to_end(&mut data)?; - - Ok(data) + Ok(plain_text) } pub fn normalize_setup_code(s: &str) -> String { @@ -663,40 +617,17 @@ fn import_self_keys(context: &Context, dir: impl AsRef) -> Result<()> { continue; } } - let ccontent = if let Ok(content) = dc_read_file(context, &path_plus_name) { - key = String::from_utf8_lossy(&content).to_string(); - CString::new(content).unwrap_or_default() - } else { - continue; - }; - - /* only import if we have a private key */ - let mut buf2_headerline = String::default(); - let split_res: bool; - unsafe { - let buf2 = dc_strdup(ccontent.as_ptr()); - split_res = dc_split_armored_data( - buf2, - &mut buf2_headerline, - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - ); - libc::free(buf2 as *mut libc::c_void); + match dc_read_file(context, &path_plus_name) { + Ok(buf) => { + let armored = std::string::String::from_utf8_lossy(&buf); + if let Err(err) = set_self_key(context, &armored, set_default, false) { + error!(context, "set_self_key: {}", err); + continue; + } + } + Err(_) => continue, } - if split_res - && buf2_headerline.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----") - && !key.contains("-----BEGIN PGP PRIVATE KEY BLOCK") - { - info!(context, "ignoring public key file '{}", name_f); - // it's fine: DC exports public with private - continue; - } - if let Err(err) = set_self_key(context, &key, set_default, false) { - error!(context, "set_self_key: {}", err); - continue; - } - imported_cnt += 1 + imported_cnt += 1; } ensure!( imported_cnt > 0, @@ -784,6 +715,7 @@ mod tests { use super::*; use crate::test_utils::*; + use pgp::armor::BlockType; #[test] fn test_render_setup_file() { @@ -866,50 +798,26 @@ mod tests { let ctx = dummy_context(); let context = &ctx.ctx; - let mut headerline = String::default(); - let mut setupcodebegin = ptr::null(); - let mut preferencrypt = ptr::null(); + let buf_1 = S_EM_SETUPFILE.as_bytes().to_vec(); + let (typ, headers, base64) = split_armored_data(&buf_1).unwrap(); + assert_eq!(typ, BlockType::Message); + assert!(S_EM_SETUPCODE.starts_with(headers.get(HEADER_SETUPCODE).unwrap())); + assert!(headers.get(HEADER_AUTOCRYPT).is_none()); - unsafe { - let buf_1 = S_EM_SETUPFILE.strdup(); - let res = dc_split_armored_data( - buf_1, - &mut headerline, - &mut setupcodebegin, - &mut preferencrypt, - ptr::null_mut(), - ); - libc::free(buf_1 as *mut libc::c_void); - assert!(res); - } - assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----"); - assert!(!setupcodebegin.is_null()); - - // TODO: verify that this is the right check - assert!(S_EM_SETUPCODE.starts_with(as_str(setupcodebegin))); - - assert!(preferencrypt.is_null()); + assert!(!base64.is_empty()); let mut setup_file = S_EM_SETUPFILE.to_string(); - let decrypted = unsafe { - decrypt_setup_file(context, S_EM_SETUPCODE, setup_file.as_bytes_mut()).unwrap() - }; + let decrypted = decrypt_setup_file( + context, + S_EM_SETUPCODE, + std::io::Cursor::new(setup_file.as_bytes()), + ) + .unwrap(); - unsafe { - let buf1 = decrypted.strdup(); - assert!(dc_split_armored_data( - buf1, - &mut headerline, - &mut setupcodebegin, - &mut preferencrypt, - ptr::null_mut(), - )); - libc::free(buf1 as *mut libc::c_void); - } + let (typ, headers, base64) = split_armored_data(&buf_1).unwrap(); - assert_eq!(headerline, "-----BEGIN PGP PRIVATE KEY BLOCK-----"); - assert!(setupcodebegin.is_null()); - assert!(!preferencrypt.is_null()); - assert_eq!(as_str(preferencrypt), "mutual",); + assert_eq!(typ, BlockType::PrivateKey); + assert_eq!(headers.get(HEADER_AUTOCRYPT), Some(&"mutual".to_string())); + assert!(headers.get(HEADER_SETUPCODE).is_none()); } } diff --git a/src/message.rs b/src/message.rs index 859700b3e..2be05289a 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,5 +1,4 @@ use std::path::{Path, PathBuf}; -use std::ptr; use deltachat_derive::{FromSql, ToSql}; @@ -107,6 +106,7 @@ impl Message { msg.hidden = row.get(18)?; msg.location_id = row.get(19)?; msg.chat_blocked = row.get::<_, Option>(20)?.unwrap_or_default(); + Ok(msg) }) } @@ -339,23 +339,10 @@ impl Message { } if let Some(filename) = self.get_file(context) { - if let Ok(mut buf) = dc_read_file(context, filename) { - unsafe { - // just a pointer inside buf, MUST NOT be free()'d - let mut buf_headerline = String::default(); - // just a pointer inside buf, MUST NOT be free()'d - let mut buf_setupcodebegin = ptr::null(); - - if dc_split_armored_data( - buf.as_mut_ptr().cast(), - &mut buf_headerline, - &mut buf_setupcodebegin, - ptr::null_mut(), - ptr::null_mut(), - ) && buf_headerline == "-----BEGIN PGP MESSAGE-----" - && !buf_setupcodebegin.is_null() - { - return Some(to_string_lossy(buf_setupcodebegin)); + if let Ok(ref buf) = dc_read_file(context, filename) { + if let Ok((typ, headers, _)) = split_armored_data(buf) { + if typ == pgp::armor::BlockType::Message { + return headers.get(crate::pgp::HEADER_SETUPCODE).cloned(); } } } diff --git a/src/pgp.rs b/src/pgp.rs index 8719c87bd..9fb3b795e 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -1,9 +1,8 @@ -use std::collections::HashSet; +use std::collections::{BTreeMap, HashSet}; use std::convert::TryInto; use std::io::Cursor; -use std::ptr; -use libc::{strchr, strlen, strncmp, strspn, strstr}; +use pgp::armor::BlockType; use pgp::composed::{ Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey, SignedSecretKey, SubkeyParamsBuilder, @@ -12,122 +11,39 @@ use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm}; use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait, StringToKey}; use rand::thread_rng; -use crate::dc_tools::*; use crate::error::Error; use crate::key::*; use crate::keyring::*; -pub unsafe fn dc_split_armored_data( - buf: *mut libc::c_char, - ret_headerline: *mut String, - ret_setupcodebegin: *mut *const libc::c_char, - ret_preferencrypt: *mut *const libc::c_char, - ret_base64: *mut *const libc::c_char, -) -> bool { - let mut success = false; - let mut line_chars: libc::size_t = 0; - let mut line: *mut libc::c_char = buf; - let mut p1: *mut libc::c_char = buf; - let mut p2: *mut libc::c_char; - let mut headerline: *mut libc::c_char = ptr::null_mut(); - let mut base64: *mut libc::c_char = ptr::null_mut(); - if !ret_setupcodebegin.is_null() { - *ret_setupcodebegin = ptr::null_mut(); - } - if !ret_preferencrypt.is_null() { - *ret_preferencrypt = ptr::null(); - } - if !ret_base64.is_null() { - *ret_base64 = ptr::null(); - } - if !buf.is_null() { - dc_remove_cr_chars(buf); - while 0 != *p1 { - if i32::from(*p1) == '\n' as i32 { - *line.offset(line_chars as isize) = 0i32 as libc::c_char; - if headerline.is_null() { - dc_trim(line); - if strncmp( - line, - b"-----BEGIN \x00" as *const u8 as *const libc::c_char, - 1, - ) == 0i32 - && strncmp( - &mut *line.offset(strlen(line).wrapping_sub(5) as isize), - b"-----\x00" as *const u8 as *const libc::c_char, - 5, - ) == 0i32 - { - headerline = line; - *ret_headerline = as_str(headerline).to_string(); - } - } else if strspn(line, b"\t\r\n \x00" as *const u8 as *const libc::c_char) - == strlen(line) - { - base64 = p1.offset(1isize); - break; - } else { - p2 = strchr(line, ':' as i32); - if p2.is_null() { - *line.add(line_chars) = '\n' as i32 as libc::c_char; - base64 = line; - break; - } else { - *p2 = 0i32 as libc::c_char; - dc_trim(line); - if strcasecmp( - line, - b"Passphrase-Begin\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - { - p2 = p2.offset(1isize); - dc_trim(p2); - if !ret_setupcodebegin.is_null() { - *ret_setupcodebegin = p2 - } - } else if strcasecmp( - line, - b"Autocrypt-Prefer-Encrypt\x00" as *const u8 as *const libc::c_char, - ) == 0i32 - { - p2 = p2.offset(1isize); - dc_trim(p2); - if !ret_preferencrypt.is_null() { - *ret_preferencrypt = p2 - } - } - } - } - p1 = p1.offset(1isize); - line = p1; - line_chars = 0; - } else { - p1 = p1.offset(1isize); - line_chars = line_chars.wrapping_add(1) - } - } - if !(headerline.is_null() || base64.is_null()) { - /* now, line points to beginning of base64 data, search end */ - /*the trailing space makes sure, this is not a normal base64 sequence*/ - p1 = strstr(base64, b"-----END \x00" as *const u8 as *const libc::c_char); - if !(p1.is_null() - || strncmp( - p1.offset(9isize), - headerline.offset(11isize), - strlen(headerline.offset(11isize)), - ) != 0i32) - { - *p1 = 0i32 as libc::c_char; - dc_trim(base64); - if !ret_base64.is_null() { - *ret_base64 = base64 - } - success = true; - } - } - } +pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt"; +pub const HEADER_SETUPCODE: &str = "passphrase-begin"; - success +/// Split data from PGP Armored Data as defined in https://tools.ietf.org/html/rfc4880#section-6.2. +/// +/// Returns (type, headers, base64 encoded body). +pub fn split_armored_data( + buf: &[u8], +) -> Result<(BlockType, BTreeMap, Vec), Error> { + use std::io::Read; + + let cursor = Cursor::new(buf); + let mut dearmor = pgp::armor::Dearmor::new(cursor); + + let mut bytes = Vec::with_capacity(buf.len()); + + dearmor.read_to_end(&mut bytes)?; + ensure!(dearmor.typ.is_some(), "Failed to parse type"); + + let typ = dearmor.typ.unwrap(); + + // normalize headers + let headers = dearmor + .headers + .into_iter() + .map(|(key, value)| (key.to_lowercase(), value)) + .collect(); + + Ok((typ, headers, bytes)) } /// Create a new key pair. @@ -281,8 +197,11 @@ pub fn dc_pgp_symm_encrypt(passphrase: &str, plain: &[u8]) -> Result Result, Error> { - let enc_msg = Message::from_bytes(Cursor::new(ctext))?; +pub fn dc_pgp_symm_decrypt( + passphrase: &str, + ctext: T, +) -> Result, Error> { + let (enc_msg, _) = Message::from_armor_single(ctext)?; let decryptor = enc_msg.decrypt_with_password(|| passphrase.into())?; let msgs = decryptor.collect::, _>>()?; @@ -293,3 +212,59 @@ pub fn dc_pgp_symm_decrypt(passphrase: &str, ctext: &[u8]) -> Result, Er None => bail!("Decrypted message is empty"), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_split_armored_data() { + let (typ, _headers, base64) = split_armored_data( + b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\naGVsbG8gd29ybGQ=\n-----END PGP MESSAGE----", + ) + .unwrap(); + + assert_eq!(typ, BlockType::Message); + assert!(!base64.is_empty()); + assert_eq!( + std::string::String::from_utf8(base64).unwrap(), + "hello world" + ); + + let (typ, _headers, base64) = + split_armored_data(b"-----BEGIN PGP MESSAGE-----\n\ndat1\n-----END PGP MESSAGE-----\n-----BEGIN PGP MESSAGE-----\n\ndat2\n-----END PGP MESSAGE-----") + .unwrap(); + + assert_eq!(typ, BlockType::Message); + assert!(!base64.is_empty()); + + let (typ, _headers, base64) = split_armored_data( + b"foo \n -----BEGIN PGP MESSAGE----- \n base64-123 \n -----END PGP MESSAGE-----", + ) + .unwrap(); + + assert_eq!(typ, BlockType::Message); + assert!(!base64.is_empty()); + + assert!(split_armored_data(b"foo-----BEGIN PGP MESSAGE-----",).is_err()); + + let (typ, headers, base64) = split_armored_data( + b"foo \n -----BEGIN PGP MESSAGE-----\n Passphrase-BeGIN : 23 \n \n base64-567 \r\n abc \n -----END PGP MESSAGE-----\n\n\n", + ) + .unwrap(); + + assert_eq!(typ, BlockType::Message); + assert!(!base64.is_empty()); + + assert_eq!(headers.get(HEADER_SETUPCODE), Some(&"23".to_string())); + + let (typ, headers, base64) = split_armored_data( + b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n Autocrypt-Prefer-Encrypt : mutual \n\nbase64\n-----END PGP PRIVATE KEY BLOCK-----" + ) + .unwrap(); + + assert_eq!(typ, BlockType::PrivateKey); + assert!(!base64.is_empty()); + assert_eq!(headers.get(HEADER_AUTOCRYPT), Some(&"mutual".to_string())); + } +} diff --git a/tests/stress.rs b/tests/stress.rs index 0c303179f..4adfd6c1c 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -1,18 +1,15 @@ //! Stress some functions for testing; if used as a lib, this file is obsolete. use std::collections::HashSet; -use std::ptr; use deltachat::chat::{self, Chat}; use deltachat::config; use deltachat::contact::*; use deltachat::context::*; -use deltachat::dc_tools::*; use deltachat::keyring::*; use deltachat::oauth2::*; use deltachat::pgp::*; use deltachat::Event; -use libc::{free, strcmp, strdup}; use tempfile::{tempdir, TempDir}; /* some data used for testing @@ -50,135 +47,6 @@ unsafe fn stress_functions(context: &Context) { assert!(res.contains(" configured_send_port ")); assert!(res.contains(" configured_server_flags ")); - let mut buf_0: *mut libc::c_char; - let mut headerline = String::default(); - let mut setupcodebegin: *const libc::c_char = ptr::null(); - let mut preferencrypt: *const libc::c_char = ptr::null(); - let mut base64: *const libc::c_char = ptr::null(); - buf_0 = strdup( - b"-----BEGIN PGP MESSAGE-----\nNoVal:\n\ndata\n-----END PGP MESSAGE-----\x00" as *const u8 - as *const libc::c_char, - ); - let ok = dc_split_armored_data( - buf_0, - &mut headerline, - &mut setupcodebegin, - ptr::null_mut(), - &mut base64, - ); - assert!(ok); - assert!(!headerline.is_empty()); - assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----"); - - assert!(!base64.is_null()); - assert_eq!(as_str(base64 as *const libc::c_char), "data",); - - free(buf_0 as *mut libc::c_void); - - buf_0 = - strdup(b"-----BEGIN PGP MESSAGE-----\n\ndat1\n-----END PGP MESSAGE-----\n-----BEGIN PGP MESSAGE-----\n\ndat2\n-----END PGP MESSAGE-----\x00" - as *const u8 as *const libc::c_char); - let ok = dc_split_armored_data( - buf_0, - &mut headerline, - &mut setupcodebegin, - ptr::null_mut(), - &mut base64, - ); - - assert!(ok); - assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----"); - - assert!(!base64.is_null()); - assert_eq!(as_str(base64 as *const libc::c_char), "dat1",); - - free(buf_0 as *mut libc::c_void); - - buf_0 = strdup( - b"foo \n -----BEGIN PGP MESSAGE----- \n base64-123 \n -----END PGP MESSAGE-----\x00" - as *const u8 as *const libc::c_char, - ); - let ok = dc_split_armored_data( - buf_0, - &mut headerline, - &mut setupcodebegin, - ptr::null_mut(), - &mut base64, - ); - - assert!(ok); - assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----"); - assert!(setupcodebegin.is_null()); - - assert!(!base64.is_null()); - assert_eq!(as_str(base64 as *const libc::c_char), "base64-123",); - - free(buf_0 as *mut libc::c_void); - - buf_0 = strdup(b"foo-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char); - let ok = dc_split_armored_data( - buf_0, - &mut headerline, - &mut setupcodebegin, - ptr::null_mut(), - &mut base64, - ); - - assert!(!ok); - free(buf_0 as *mut libc::c_void); - buf_0 = - strdup(b"foo \n -----BEGIN PGP MESSAGE-----\n Passphrase-BeGIN : 23 \n \n base64-567 \r\n abc \n -----END PGP MESSAGE-----\n\n\n\x00" - as *const u8 as *const libc::c_char); - let ok = dc_split_armored_data( - buf_0, - &mut headerline, - &mut setupcodebegin, - ptr::null_mut(), - &mut base64, - ); - assert!(ok); - assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----"); - - assert!(!setupcodebegin.is_null()); - assert_eq!( - strcmp( - setupcodebegin, - b"23\x00" as *const u8 as *const libc::c_char, - ), - 0 - ); - - assert!(!base64.is_null()); - assert_eq!(as_str(base64 as *const libc::c_char), "base64-567 \n abc",); - - free(buf_0 as *mut libc::c_void); - - buf_0 = - strdup(b"-----BEGIN PGP PRIVATE KEY BLOCK-----\n Autocrypt-Prefer-Encrypt : mutual \n\nbase64\n-----END PGP PRIVATE KEY BLOCK-----\x00" - as *const u8 as *const libc::c_char); - let ok = dc_split_armored_data( - buf_0, - &mut headerline, - ptr::null_mut(), - &mut preferencrypt, - &mut base64, - ); - assert!(ok); - assert_eq!(headerline, "-----BEGIN PGP PRIVATE KEY BLOCK-----"); - assert!(!preferencrypt.is_null()); - assert_eq!( - strcmp( - preferencrypt, - b"mutual\x00" as *const u8 as *const libc::c_char, - ), - 0 - ); - - assert!(!base64.is_null()); - assert_eq!(as_str(base64 as *const libc::c_char), "base64",); - - free(buf_0 as *mut libc::c_void); - // Cant check, no configured context // assert!(dc_is_configured(context) != 0, "Missing configured context");