diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 2b5f74c72..d34a7bdbb 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -407,7 +407,7 @@ unsafe fn log_msglist(context: &dc_context_t, msglist: *mut dc_array_t) { } unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) { let mut contact: *mut dc_contact_t; - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); if !dc_array_search_id(contacts, 1i32 as uint32_t, 0 as *mut size_t) { dc_array_add_id(contacts, 1i32 as uint32_t); } @@ -444,18 +444,21 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) { b"addr unset\x00" as *const u8 as *const libc::c_char }, ); - let peerstate_ok: libc::c_int = - dc_apeerstate_load_by_addr(peerstate, &context.sql.clone().read().unwrap(), addr); + let peerstate_ok: libc::c_int = dc_apeerstate_load_by_addr( + &mut peerstate, + &context.sql.clone().read().unwrap(), + addr, + ); if 0 != peerstate_ok && contact_id != 1i32 as libc::c_uint { let pe: *mut libc::c_char; - match (*peerstate).prefer_encrypt { + match peerstate.prefer_encrypt { 1 => pe = dc_strdup(b"mutual\x00" as *const u8 as *const libc::c_char), 0 => pe = dc_strdup(b"no-preference\x00" as *const u8 as *const libc::c_char), 20 => pe = dc_strdup(b"reset\x00" as *const u8 as *const libc::c_char), _ => { pe = dc_mprintf( b"unknown-value (%i)\x00" as *const u8 as *const libc::c_char, - (*peerstate).prefer_encrypt, + peerstate.prefer_encrypt, ) } } @@ -485,7 +488,7 @@ unsafe fn log_contactlist(context: &dc_context_t, contacts: *mut dc_array_t) { } i += 1 } - dc_apeerstate_unref(peerstate); + dc_apeerstate_unref(&mut peerstate); } static mut s_is_auth: libc::c_int = 0i32; diff --git a/src/dc_aheader.rs b/src/dc_aheader.rs index bb32e6354..8b4347ff3 100644 --- a/src/dc_aheader.rs +++ b/src/dc_aheader.rs @@ -4,7 +4,6 @@ use std::str::FromStr; use std::{fmt, str}; use mmime::mailimf_types::*; -use num_traits::ToPrimitive; use crate::constants::*; use crate::dc_contact::*; @@ -157,9 +156,13 @@ impl str::FromStr for Aheader { } }; - let public_key = match attributes.remove("keydata") { - Some(raw) => Key::from_base64(raw, KeyType::Public), + let public_key = match attributes + .remove("keydata") + .and_then(|raw| Key::from_base64(&raw, KeyType::Public)) + { + Some(key) => key, None => { + println!("invalid key"); return Err(()); } }; @@ -189,10 +192,9 @@ impl str::FromStr for Aheader { #[cfg(test)] mod tests { use super::*; - use crate::pgp as rpgp; fn rawkey() -> String { - "mDMEWFUX7RYJKwYBBAHaRw8BAQdACHq6FkRGsHqBMsNpD7d+aQ2jtxVwTO+Y4NhBaQyHaMj+0HWFsaWNlQHRlc3RzdWl0ZS5hdXRvY3J5cHQub3JniJAEExYIADgWIQQmqmdR/XZoxC+kkkr8dE2p/nPD1AUCWFUX7QIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRD8dE2p/nPD1EqOAP0WUDKwko001X7XTSYbWGWmXfR9P1Aw6917EnkVQMsp3gEA86Ii8ArL3jd+E2qS5JSysx/qiVhuTSwWzmC5K6zKdg+4OARYVRfuEgorBgEEAZdVAQUBAQdAv1A88FoCfwz0zSh6NNnUuKuz1p3ctJ3kXMGotsVYjA0DAQgHiHgEGBYIACAWIQQmqmdR/XZoxC+kkkr8dE2p/nPD1AUCWFUX7gIbDAAKCRD8dE2p/nPD1FTOAP4nS14sX7a/nBXBKWAh/oX8iVtkhmZqjy9tG21BcNqb+wEAq73H4+1ncnkscR3Nu4GYzNRSD3NXq68tEESK28kYvw4=".into() + "xsBNBFzG3j0BCAC6iNhT8zydvCXi8LI/gFnkadMbfmSE/rTJskRRra/utGbLyDta/yTrJgWL7O3y/g4HdDW/dN2z26Y6W13IMzx9gLInn1KQZChtqWAcr/ReUucXcymwcfg1mdkBGk3TSLeLihN6CJx8Wsv8ig+kgAzte4f5rqEEAJVQ9WZHuti7UiYs6oRzqTo06CRe9owVXxzdMf0VDQtf7ZFm9dpzKKbhH7Lu8880iiotQ9/yRCkDGp9fNThsrLdZiK6OIAcIBAqi2rI89aS1dAmnRbktQieCx5izzyYkR1KvVL3gTTllHOzfKVEC2asmtWu2e4se/+O4WMIS1eGrn7GeWVb0Vwc5ABEBAAHNETxhQEBiLmV4YW1wbGUuZGU+wsCJBBABCAAzAhkBBQJcxt5FAhsDBAsJCAcGFQgJCgsCAxYCARYhBI4xxYKBgH3ANh5cufaKrc9mtiMLAAoJEPaKrc9mtiML938H/18F+3Wf9/JaAy/8hCO1v4S2PVBhxaKCokaNFtkfaMRne2l087LscCFPiFNyb4mv6Z3YeK8Xpxlp2sI0ecvdiqLUOGfnxS6tQrj+83EjtIrZ/hXOk1h121QFWH9Zg2VNHtODXjAgdLDC0NWUrclR0ZOqEDQHeo0ibTILdokVfXFN25wakPmGaYJP2y729cb1ve7RzvIvwn+Dddfxo3ao72rBfLi7l4NQ4S0KsY4cw+/6l5bRCKYCP77wZtvCwUvfVVosLdT43agtSiBI49+ayqvZ8OCvSJa61i+v81brTiEy9GBod4eAp45Ibsuemkw+gon4ZOvUXHTjwFB+h63MrozOwE0EXMbePQEIAL/vauf1zK8JgCu3V+G+SOX0iWw5xUlCPX+ERpBbWfwu3uAqn4wYXD3JDE/fVAF668xiV4eTPtlSUd5h0mn+G7uXMMOtkb+20SoEt50f8zw8TrL9t+ZsV11GKZWJpCar5AhXWsn6EEi8I2hLL5vn55ZZmHuGgN4jjmkRl3ToKCLhaXwTBjCJem7N5EH7F75wErEITa55v4Lb4Nfca7vnvtYrI1OA446xa8gHra0SINelTD09/JM/Fw4sWVPBaRZmJK/Tnu79N23No9XBUubmFPv1pNexZsQclicnTpt/BEWhiun7d6lfGB63K1aoHRTR1pcrWvBuALuuz0gqar2zlI0AEQEAAcLAdgQYAQgAIAUCXMbeRQIbDBYhBI4xxYKBgH3ANh5cufaKrc9mtiMLAAoJEPaKrc9mtiMLKSEIAIyLCRO2OyZ0IYRvRPpMn4p7E+7Pfcz/0mSkOy+1hshgJnqivXurm8zwGrwdMqeV4eslKR9H1RUdWGUQJNbtwmmjrt5DHpIhYHl5t3FpCBaGbV20Omo00Q38lBl9MtrmZkZw+ktEk6X+0xCKssMF+2MADkSOIufbR5HrDVB89VZOHCO9DeXvCUUAw2hyJiL/LHmLzJ40zYoTmb+F//f0k0j+tRdbkefyRoCmwG7YGiT+2hnCdgcezswnzah5J3ZKlrg7jOGo1LxtbvNUzxNBbC6S/aNgwm6qxo7xegRhmEl5uZ16zwyj4qz+xkjGy25Of5mWfUDoNw7OT7sjUbHOOMc=".into() } #[test] @@ -206,7 +208,6 @@ mod tests { assert_eq!(h.addr, "me@mail.com"); assert_eq!(h.prefer_encrypt, EncryptPreference::Mutual); - assert!(!h.public_key.is_null()); } #[test] @@ -216,7 +217,6 @@ mod tests { assert_eq!(h.addr, "me@mail.com"); assert_eq!(h.prefer_encrypt, EncryptPreference::NoPreference); - assert!(!h.public_key.is_null()); } #[test] @@ -234,32 +234,22 @@ mod tests { let ah = Aheader::from_str(fixed_header).expect("failed to parse"); assert_eq!(ah.addr, "a@b.example.org"); - // assert_eq!(unsafe { (*ah.public_key).bytes }, 1212); - assert!(valid_key(ah.public_key as *const _)); assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual); let rendered = ah.to_string(); assert_eq!(rendered, fixed_header); - let ah = Aheader::from_str(" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = RG VsdGEgQ\r\n2hhdA==").expect("failed to parse"); + let ah = Aheader::from_str(&format!(" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = {}", rawkey())).expect("failed to parse"); assert_eq!(ah.addr, "a@b.example.org"); - assert_eq!(unsafe { (*ah.public_key).bytes }, 10); assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual); - assert_eq!( - unsafe { - CStr::from_ptr((*ah.public_key).binary as *const _) - .to_str() - .unwrap() - }, - "Delta Chat" - ); - Aheader::from_str( - "addr=a@b.example.org; prefer-encrypt=ignoreUnknownValues; keydata=RGVsdGEgQ2hhdA==", - ) + Aheader::from_str(&format!( + "addr=a@b.example.org; prefer-encrypt=ignoreUnknownValues; keydata={}", + rawkey() + )) .expect("failed to parse"); - Aheader::from_str("addr=a@b.example.org; keydata=RGVsdGEgQ2hhdA==") + Aheader::from_str(&format!("addr=a@b.example.org; keydata={}", rawkey())) .expect("failed to parse"); } @@ -271,29 +261,4 @@ mod tests { assert!(Aheader::from_str(" ;;").is_err()); assert!(Aheader::from_str("addr=a@t.de; unknwon=1; keydata=jau").is_err()); } - - fn valid_key(raw_key: *const dc_key_t) -> bool { - let mut key_is_valid = false; - unsafe { - if !(raw_key.is_null() || (*raw_key).binary.is_null() || (*raw_key).bytes <= 0i32) { - let key = rpgp::rpgp_key_from_bytes( - (*raw_key).binary as *const _, - (*raw_key).bytes as usize, - ); - - if (*raw_key).type_0 == 0i32 && 0 != rpgp::rpgp_key_is_public(key) as libc::c_int { - key_is_valid = true; - } else if (*raw_key).type_0 == 1i32 - && 0 != rpgp::rpgp_key_is_secret(key) as libc::c_int - { - key_is_valid = true; - } - if !key.is_null() { - rpgp::rpgp_key_drop(key); - } - } - } - - key_is_valid - } } diff --git a/src/dc_apeerstate.rs b/src/dc_apeerstate.rs index 8ef3b359f..08cf7141d 100644 --- a/src/dc_apeerstate.rs +++ b/src/dc_apeerstate.rs @@ -2,6 +2,7 @@ use std::ffi::{CStr, CString}; use num_traits::ToPrimitive; +use crate::constants::*; use crate::dc_aheader::*; use crate::dc_chat::*; use crate::dc_context::dc_context_t; @@ -104,11 +105,10 @@ pub unsafe fn dc_apeerstate_init_from_header( // TODO should return bool /rtn pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) -> libc::c_int { - let mut success: libc::c_int = 0i32; let mut old_public_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char; let mut old_gossip_fingerprint: *mut libc::c_char = 0 as *mut libc::c_char; - if let Some(public_key) = peerstate.public_key { + if let Some(ref public_key) = peerstate.public_key { old_public_fingerprint = peerstate.public_key_fingerprint; peerstate.public_key_fingerprint = public_key.fingerprint_c(); if old_public_fingerprint.is_null() @@ -126,7 +126,7 @@ pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) } } - if let Some(gossip_key) = peerstate.gossip_key { + if let Some(ref gossip_key) = peerstate.gossip_key { old_gossip_fingerprint = peerstate.gossip_key_fingerprint; peerstate.gossip_key_fingerprint = gossip_key.fingerprint_c(); @@ -144,12 +144,11 @@ pub unsafe fn dc_apeerstate_recalc_fingerprint(peerstate: &mut dc_apeerstate_t) } } } - success = 1i32; free(old_public_fingerprint as *mut libc::c_void); free(old_gossip_fingerprint as *mut libc::c_void); - success + 1 } // TODO should return bool /rtn @@ -215,8 +214,8 @@ pub unsafe fn dc_apeerstate_apply_header( peerstate.to_save |= 0x2i32 } - if peerstate.public_key == Some(header.public_key) { - peerstate.public_key = Some(header.public_key); + if peerstate.public_key.as_ref() == Some(&header.public_key) { + peerstate.public_key = Some(header.public_key.clone()); dc_apeerstate_recalc_fingerprint(peerstate); peerstate.to_save |= 0x2i32; } @@ -241,7 +240,7 @@ pub unsafe fn dc_apeerstate_apply_gossip( if message_time > peerstate.gossip_timestamp { peerstate.gossip_timestamp = message_time; peerstate.to_save |= 0x1i32; - if peerstate.gossip_key == Some(gossip_header.public_key) { + if peerstate.gossip_key.as_ref() == Some(&gossip_header.public_key) { peerstate.gossip_key = Some(gossip_header.public_key.clone()); dc_apeerstate_recalc_fingerprint(peerstate); peerstate.to_save |= 0x2i32 @@ -258,16 +257,19 @@ pub unsafe fn dc_apeerstate_render_gossip_header( } let addr = CStr::from_ptr(peerstate.addr).to_str().unwrap().into(); - let key = dc_apeerstate_peek_key(peerstate, min_verified).clone(); - let header = Aheader::new(addr, key, EncryptPreference::NoPreference); - let rendered = header.to_string(); - let rendered_c = CString::new(rendered).unwrap(); + if let Some(key) = dc_apeerstate_peek_key(peerstate, min_verified) { + // TODO: avoid cloning + let header = Aheader::new(addr, key.clone(), EncryptPreference::NoPreference); + let rendered = header.to_string(); + let rendered_c = CString::new(rendered).unwrap(); + return libc::strdup(rendered_c.as_ptr()); + } - libc::strdup(rendered_c.as_ptr()) + std::ptr::null_mut() } pub unsafe fn dc_apeerstate_peek_key<'a>( - peerstate: &dc_apeerstate_t<'a>, + peerstate: &'a dc_apeerstate_t<'a>, min_verified: libc::c_int, ) -> Option<&'a Key> { if peerstate.public_key.is_none() @@ -303,7 +305,7 @@ pub unsafe fn dc_apeerstate_set_verified( && strcasecmp(peerstate.public_key_fingerprint, fingerprint) == 0 { peerstate.to_save |= 0x2; - peerstate.verified_key = Some(peerstate.public_key.clone()); + peerstate.verified_key = peerstate.public_key.clone(); peerstate.verified_key_fingerprint = dc_strdup(peerstate.public_key_fingerprint); success = 1 } @@ -314,7 +316,7 @@ pub unsafe fn dc_apeerstate_set_verified( && strcasecmp(peerstate.gossip_key_fingerprint, fingerprint) == 0 { peerstate.to_save |= 0x2; - peerstate.verified_key = Some(peerstate.gossip_key.clone()); + peerstate.verified_key = peerstate.gossip_key.clone(); peerstate.verified_key_fingerprint = dc_strdup(peerstate.gossip_key_fingerprint); success = 1 } @@ -364,13 +366,13 @@ unsafe fn dc_apeerstate_set_from_stmt( dc_strdup(sqlite3_column_text(stmt, 10) as *mut libc::c_char); if sqlite3_column_type(stmt, 4) != 5 { - peerstate.public_key = Key::from_stmt(stmt, 4, 0); + peerstate.public_key = Key::from_stmt(stmt, 4, KeyType::Public); } if sqlite3_column_type(stmt, 6) != 5 { - peerstate.gossip_key = Key::from_stmt(stmt, 6, 0); + peerstate.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public); } if sqlite3_column_type(stmt, 9) != 5 { - peerstate.verified_key = Key::from_stmt(stmt, 9, 0); + peerstate.verified_key = Key::from_stmt(stmt, 9, KeyType::Public); } } @@ -434,54 +436,49 @@ pub unsafe fn dc_apeerstate_save_to_db( sqlite3_bind_int64(stmt, 1, peerstate.last_seen as sqlite3_int64); sqlite3_bind_int64(stmt, 2, peerstate.last_seen_autocrypt as sqlite3_int64); sqlite3_bind_int64(stmt, 3, peerstate.prefer_encrypt as sqlite3_int64); - sqlite3_bind_blob( - stmt, - 4, - if !peerstate.public_key.is_null() { - (*peerstate.public_key).binary - } else { - 0 as *mut libc::c_void - }, - if !peerstate.public_key.is_null() { - (*peerstate.public_key).bytes - } else { - 0 - }, - None, - ); + + if let Some(ref key) = peerstate.public_key { + let b = key.to_bytes(); + sqlite3_bind_blob( + stmt, + 4, + b.as_ptr() as *const _, + b.len() as libc::c_int, + None, + ); + } else { + sqlite3_bind_blob(stmt, 4, std::ptr::null(), 0, None); + } + sqlite3_bind_int64(stmt, 5, peerstate.gossip_timestamp as sqlite3_int64); - sqlite3_bind_blob( - stmt, - 6, - if !peerstate.gossip_key.is_null() { - (*peerstate.gossip_key).binary - } else { - 0 as *mut libc::c_void - }, - if !peerstate.gossip_key.is_null() { - (*peerstate.gossip_key).bytes - } else { - 0 - }, - None, - ); + if let Some(ref key) = peerstate.gossip_key { + let b = key.to_bytes(); + sqlite3_bind_blob( + stmt, + 6, + b.as_ptr() as *const _, + b.len() as libc::c_int, + None, + ); + } else { + sqlite3_bind_blob(stmt, 6, std::ptr::null(), 0, None); + } + sqlite3_bind_text(stmt, 7, peerstate.public_key_fingerprint, -1, None); sqlite3_bind_text(stmt, 8, peerstate.gossip_key_fingerprint, -1, None); - sqlite3_bind_blob( - stmt, - 9, - if !peerstate.verified_key.is_null() { - (*peerstate.verified_key).binary - } else { - 0 as *mut libc::c_void - }, - if !peerstate.verified_key.is_null() { - (*peerstate.verified_key).bytes - } else { - 0 - }, - None, - ); + if let Some(ref key) = peerstate.verified_key { + let b = key.to_bytes(); + sqlite3_bind_blob( + stmt, + 9, + b.as_ptr() as *const _, + b.len() as libc::c_int, + None, + ); + } else { + sqlite3_bind_blob(stmt, 9, std::ptr::null(), 0, None); + } + sqlite3_bind_text(stmt, 10, peerstate.verified_key_fingerprint, -1, None); sqlite3_bind_text(stmt, 11, peerstate.addr, -1, None); if sqlite3_step(stmt) != 101 { diff --git a/src/dc_contact.rs b/src/dc_contact.rs index 23175d03c..1d425aaf2 100644 --- a/src/dc_contact.rs +++ b/src/dc_contact.rs @@ -797,9 +797,10 @@ pub unsafe fn dc_get_contact_encrinfo( ); let mut self_key = Key::from_self_public( context, - (*loginparam).addr & context.sql.clone().read().unwrap(), + (*loginparam).addr, + &context.sql.clone().read().unwrap(), ); - if !dc_apeerstate_peek_key(&peerstate, 0).is_null() { + if dc_apeerstate_peek_key(&peerstate, 0).is_some() { p = dc_stock_str( context, if peerstate.prefer_encrypt == 1i32 { @@ -828,7 +829,6 @@ pub unsafe fn dc_get_contact_encrinfo( .map(|k| k.formatted_fingerprint_c()) .unwrap_or(std::ptr::null_mut()); fingerprint_other_verified = dc_apeerstate_peek_key(&peerstate, 2) - .map .map(|k| k.formatted_fingerprint_c()) .unwrap_or(std::ptr::null_mut()); fingerprint_other_unverified = dc_apeerstate_peek_key(&peerstate, 0) @@ -874,7 +874,7 @@ pub unsafe fn dc_get_contact_encrinfo( } } - dc_apeerstate_unref(peerstate); + dc_apeerstate_unref(&mut peerstate); dc_contact_unref(contact); dc_loginparam_unref(loginparam); @@ -1077,51 +1077,60 @@ pub unsafe fn dc_contact_is_blocked(contact: *const dc_contact_t) -> libc::c_int (*contact).blocked } +/// Check if a contact was verified. E.g. by a secure-join QR code scan +/// and if the key has not changed since this verification. +/// +/// The UI may draw a checkbox or something like that beside verified contacts. +/// +/// Returns +/// - 0: contact is not verified. +/// - 2: SELF and contact have verified their fingerprints in both directions; in the UI typically checkmarks are shown. pub unsafe fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int { - dc_contact_is_verified_ex(contact, 0 as *mut dc_apeerstate_t) + dc_contact_is_verified_ex(contact, None) } +/// Same as dc_contact_is_verified() but allows speeding up things +/// by adding the peerstate belonging to the contact. +/// If you do not have the peerstate available, it is loaded automatically. pub unsafe fn dc_contact_is_verified_ex<'a>( contact: *mut dc_contact_t<'a>, - mut peerstate: *mut dc_apeerstate_t<'a>, + peerstate: Option<&dc_apeerstate_t<'a>>, ) -> libc::c_int { - let current_block: u64; - let mut contact_verified: libc::c_int = 0i32; - let mut peerstate_to_delete: *mut dc_apeerstate_t = 0 as *mut dc_apeerstate_t; - if !(contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint) { - if (*contact).id == 1i32 as libc::c_uint { - contact_verified = 2i32 - } else { - // we're always sort of secured-verified as we could verify the key on this device any time with the key on this device - if peerstate.is_null() { - peerstate_to_delete = dc_apeerstate_new((*contact).context); - if 0 == dc_apeerstate_load_by_addr( - peerstate_to_delete, - &mut (*contact).context.sql.clone().read().unwrap(), - (*contact).addr, - ) { - current_block = 8667923638376902112; - } else { - peerstate = peerstate_to_delete; - current_block = 13109137661213826276; - } - } else { - current_block = 13109137661213826276; - } - match current_block { - 8667923638376902112 => {} - _ => { - contact_verified = if !(*peerstate).verified_key.is_null() { - 2i32 - } else { - 0i32 - } - } - } - } + if contact.is_null() || (*contact).magic != 0xc047ac7i32 as libc::c_uint { + return 0; + } + + // we're always sort of secured-verified as we could verify the key on this device any time with the key + // on this device + if (*contact).id == 1 as libc::c_uint { + return 2; + } + + if let Some(peerstate) = peerstate { + if peerstate.verified_key.is_some() { + 2 + } else { + 0 + } + } else { + let mut peerstate = dc_apeerstate_new((*contact).context); + let mut res = 0; + + if 0 != dc_apeerstate_load_by_addr( + &mut peerstate, + &mut (*contact).context.sql.clone().read().unwrap(), + (*contact).addr, + ) { + res = if peerstate.verified_key.is_some() { + 2 + } else { + 0 + }; + } + dc_apeerstate_unref(&mut peerstate); + + res } - dc_apeerstate_unref(peerstate_to_delete); - contact_verified } // Working with e-mail-addresses diff --git a/src/dc_e2ee.rs b/src/dc_e2ee.rs index 7a33fe716..c896d989e 100644 --- a/src/dc_e2ee.rs +++ b/src/dc_e2ee.rs @@ -16,7 +16,6 @@ use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR}; use crate::dc_aheader::*; use crate::dc_apeerstate::*; -use crate::dc_array::*; use crate::dc_context::dc_context_t; use crate::dc_hash::*; use crate::dc_key::*; @@ -56,16 +55,14 @@ pub unsafe fn dc_e2ee_encrypt( mut in_out_message: *mut mailmime, mut helper: *mut dc_e2ee_helper_t, ) { - let current_block: u64; + let mut current_block: u64 = 0; let mut col: libc::c_int = 0i32; let mut do_encrypt: libc::c_int = 0i32; /*just a pointer into mailmime structure, must not be freed*/ let imffields_unprotected: *mut mailimf_fields; - let keyring: *mut dc_keyring_t = dc_keyring_new(); + let mut keyring = Keyring::default(); let plain: *mut MMAPString = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); - let mut ctext: *mut libc::c_char = 0 as *mut libc::c_char; - let mut ctext_bytes: size_t = 0i32 as size_t; - let peerstates = dc_array_new(10i32 as size_t); + let mut peerstates = Vec::new(); if !helper.is_null() { memset( helper as *mut libc::c_void, @@ -77,7 +74,6 @@ pub unsafe fn dc_e2ee_encrypt( if !(recipients_addr.is_null() || in_out_message.is_null() || !(*in_out_message).mm_parent.is_null() - || keyring.is_null() || plain.is_null() || helper.is_null()) { @@ -117,19 +113,20 @@ pub unsafe fn dc_e2ee_encrypt( 0 as *mut libc::c_void }) as *const libc::c_char; - let peerstate = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); if !(strcasecmp(recipient_addr, addr) == 0i32) { if 0 != dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), recipient_addr, ) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed) { if let Some(key_to_use) = - dc_apeerstate_peek_key(peerstate, min_verified) + dc_apeerstate_peek_key(&peerstate, min_verified) { - dc_keyring_add(keyring, key_to_use); - dc_array_add_ptr(peerstates, &peerstate); + // TODO: avoid clone + keyring.add(key_to_use.clone()); + peerstates.push(peerstate); } } else { dc_apeerstate_unref(&mut peerstate); @@ -146,7 +143,8 @@ pub unsafe fn dc_e2ee_encrypt( } } let sign_key = if 0 != do_encrypt { - dc_keyring_add(keyring, public_key); + // TODO: avoid clone + keyring.add(public_key.clone()); let key = Key::from_self_private(context, addr, &context.sql.clone().read().unwrap()); @@ -184,13 +182,12 @@ pub unsafe fn dc_e2ee_encrypt( part_to_encrypt, ); if 0 != do_gossip { - let iCnt: libc::c_int = dc_array_get_cnt(peerstates) as libc::c_int; + let iCnt: libc::c_int = peerstates.len() as libc::c_int; if iCnt > 1i32 { let mut i: libc::c_int = 0i32; while i < iCnt { let p: *mut libc::c_char = dc_apeerstate_render_gossip_header( - dc_array_get_ptr(peerstates, i as size_t) - as *mut dc_apeerstate_t, + &peerstates[i as usize], min_verified, ); if !p.is_null() { @@ -303,66 +300,66 @@ pub unsafe fn dc_e2ee_encrypt( mailmime_write_mem(plain, &mut col, message_to_encrypt); if (*plain).str_0.is_null() || (*plain).len <= 0 { current_block = 14181132614457621749; - } else if 0 - == dc_pgp_pk_encrypt( - context, + } else { + if let Some(ctext_v) = dc_pgp_pk_encrypt( (*plain).str_0 as *const libc::c_void, (*plain).len, - keyring, - &sign_key, - 1, - &mut ctext as *mut *mut libc::c_char as *mut *mut libc::c_void, - &mut ctext_bytes, - ) - { - /*use_armor*/ - current_block = 14181132614457621749; - } else { - (*helper).cdata_to_free = ctext as *mut libc::c_void; - //char* t2=dc_null_terminate(ctext,ctext_bytes);printf("ENCRYPTED:\n%s\n",t2);free(t2); // DEBUG OUTPUT - /* create MIME-structure that will contain the encrypted text */ - let mut encrypted_part: *mut mailmime = new_data_part( - 0 as *mut libc::c_void, - 0i32 as size_t, - b"multipart/encrypted\x00" as *const u8 as *const libc::c_char - as *mut libc::c_char, - -1i32, - ); - let content: *mut mailmime_content = (*encrypted_part).mm_content_type; - clist_insert_after( - (*content).ct_parameters, - (*(*content).ct_parameters).last, - mailmime_param_new_with_data( - b"protocol\x00" as *const u8 as *const libc::c_char + &keyring, + sign_key.as_ref(), + ) { + let ctext_bytes = ctext_v.len(); + let ctext_c = CString::new(ctext_v).unwrap(); + let ctext = libc::strdup(ctext_c.as_ptr()); + + (*helper).cdata_to_free = ctext as *mut libc::c_void; + + /* create MIME-structure that will contain the encrypted text */ + let mut encrypted_part: *mut mailmime = new_data_part( + 0 as *mut libc::c_void, + 0i32 as size_t, + b"multipart/encrypted\x00" as *const u8 as *const libc::c_char as *mut libc::c_char, + -1i32, + ); + let content: *mut mailmime_content = + (*encrypted_part).mm_content_type; + clist_insert_after( + (*content).ct_parameters, + (*(*content).ct_parameters).last, + mailmime_param_new_with_data( + b"protocol\x00" as *const u8 as *const libc::c_char + as *mut libc::c_char, + b"application/pgp-encrypted\x00" as *const u8 + as *const libc::c_char + as *mut libc::c_char, + ) as *mut libc::c_void, + ); + static mut version_content: [libc::c_char; 13] = + [86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0]; + let version_mime: *mut mailmime = new_data_part( + version_content.as_mut_ptr() as *mut libc::c_void, + strlen(version_content.as_mut_ptr()), b"application/pgp-encrypted\x00" as *const u8 as *const libc::c_char as *mut libc::c_char, - ) as *mut libc::c_void, - ); - static mut version_content: [libc::c_char; 13] = - [86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0]; - let version_mime: *mut mailmime = new_data_part( - version_content.as_mut_ptr() as *mut libc::c_void, - strlen(version_content.as_mut_ptr()), - b"application/pgp-encrypted\x00" as *const u8 as *const libc::c_char - as *mut libc::c_char, - MAILMIME_MECHANISM_7BIT as libc::c_int, - ); - mailmime_smart_add_part(encrypted_part, version_mime); - let ctext_part: *mut mailmime = new_data_part( - ctext as *mut libc::c_void, - ctext_bytes, - b"application/octet-stream\x00" as *const u8 as *const libc::c_char - as *mut libc::c_char, - MAILMIME_MECHANISM_7BIT as libc::c_int, - ); - mailmime_smart_add_part(encrypted_part, ctext_part); - (*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part; - (*encrypted_part).mm_parent = in_out_message; - mailmime_free(message_to_encrypt); - (*helper).encryption_successfull = 1i32; - current_block = 13824533195664196414; + MAILMIME_MECHANISM_7BIT as libc::c_int, + ); + mailmime_smart_add_part(encrypted_part, version_mime); + let ctext_part: *mut mailmime = new_data_part( + ctext as *mut libc::c_void, + ctext_bytes, + b"application/octet-stream\x00" as *const u8 + as *const libc::c_char + as *mut libc::c_char, + MAILMIME_MECHANISM_7BIT as libc::c_int, + ); + mailmime_smart_add_part(encrypted_part, ctext_part); + (*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part; + (*encrypted_part).mm_parent = in_out_message; + mailmime_free(message_to_encrypt); + (*helper).encryption_successfull = 1i32; + current_block = 13824533195664196414; + } } } else { current_block = 13824533195664196414; @@ -388,16 +385,13 @@ pub unsafe fn dc_e2ee_encrypt( } } - dc_keyring_unref(keyring); if !plain.is_null() { mmap_string_free(plain); } - let mut i_0 = (dc_array_get_cnt(peerstates) as isize) - 1; - while i_0 >= 0 { - dc_apeerstate_unref(dc_array_get_ptr(peerstates, i_0 as size_t) as *mut dc_apeerstate_t); - i_0 -= 1 + + for peerstate in peerstates.iter_mut() { + dc_apeerstate_unref(peerstate); } - dc_array_unref(peerstates); } /******************************************************************************* @@ -515,14 +509,10 @@ unsafe fn new_data_part( unsafe fn load_or_generate_self_public_key( context: &dc_context_t, self_addr: *const libc::c_char, - random_data_mime: *mut mailmime, + _random_data_mime: *mut mailmime, ) -> Option { - let mut current_block: u64; /* avoid double creation (we unlock the database during creation) */ static mut s_in_key_creation: libc::c_int = 0i32; - let key_created: libc::c_int; - let mut success: libc::c_int = 0i32; - let mut key_creation_here: libc::c_int = 0i32; let mut key = Key::from_self_public(context, self_addr, &context.sql.clone().read().unwrap()); if key.is_some() { @@ -533,7 +523,7 @@ unsafe fn load_or_generate_self_public_key( if 0 != s_in_key_creation { return None; } - key_creation_here = 1; + let key_creation_here = 1; s_in_key_creation = 1; let start: libc::clock_t = clock(); @@ -545,25 +535,15 @@ unsafe fn load_or_generate_self_public_key( 65537i32, ); - if let Some((public_key, private_key)) = dc_pgp_create_keypair(context, self_addr) { - if 0 == dc_pgp_is_valid_key(context, &public_key) - || 0 == dc_pgp_is_valid_key(context, &private_key) - { - dc_log_warning( - context, - 0i32, - b"Generated keys are not valid.\x00" as *const u8 as *const libc::c_char, - ); - } else if 0 - == dc_key_save_self_keypair( - context, - &public_key, - &private_key, - self_addr, - 1i32, - &context.sql.clone().read().unwrap(), - ) - { + if let Some((public_key, private_key)) = dc_pgp_create_keypair(self_addr) { + if !dc_key_save_self_keypair( + context, + &public_key, + &private_key, + self_addr, + 1i32, + &context.sql.clone().read().unwrap(), + ) { /*set default*/ dc_log_warning( context, @@ -579,7 +559,7 @@ unsafe fn load_or_generate_self_public_key( ); } - key = public_key; + key = Some(public_key); } else { dc_log_warning( context, @@ -607,11 +587,11 @@ pub unsafe fn dc_e2ee_decrypt( /*just a pointer into mailmime structure, must not be freed*/ let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message); let mut message_time: time_t = 0i32 as time_t; - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); let mut from: *mut libc::c_char = 0 as *mut libc::c_char; let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char; - let private_keyring: *mut dc_keyring_t = dc_keyring_new(); - let public_keyring_for_validate: *mut dc_keyring_t = dc_keyring_new(); + let mut private_keyring = Keyring::default(); + let mut public_keyring_for_validate = Keyring::default(); let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields; if !helper.is_null() { memset( @@ -640,30 +620,33 @@ pub unsafe fn dc_e2ee_decrypt( } } } - let mut autocryptheader = Aheader::from_imffields(from, imffields); - if let Some(ref header) = autocryptheader { - if 0 == dc_pgp_is_valid_key(context, header.public_key) { - autocryptheader = None; - } - } + let autocryptheader = Aheader::from_imffields(from, imffields); if message_time > 0i32 as libc::c_long && !from.is_null() { if 0 != dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), from, ) { if let Some(ref header) = autocryptheader { - dc_apeerstate_apply_header(peerstate, header, message_time); - dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32); - } else if message_time > (*peerstate).last_seen_autocrypt + dc_apeerstate_apply_header(&mut peerstate, header, message_time); + dc_apeerstate_save_to_db( + &mut peerstate, + &context.sql.clone().read().unwrap(), + 0i32, + ); + } else if message_time > peerstate.last_seen_autocrypt && 0 == contains_report(in_out_message) { - dc_apeerstate_degrade_encryption(peerstate, message_time); - dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32); + dc_apeerstate_degrade_encryption(&mut peerstate, message_time); + dc_apeerstate_save_to_db( + &peerstate, + &context.sql.clone().read().unwrap(), + 0i32, + ); } } else if let Some(ref header) = autocryptheader { - dc_apeerstate_init_from_header(peerstate, header, message_time); - dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 1i32); + dc_apeerstate_init_from_header(&mut peerstate, header, message_time); + dc_apeerstate_save_to_db(&peerstate, &context.sql.clone().read().unwrap(), 1i32); } } /* load private key for decryption */ @@ -674,26 +657,24 @@ pub unsafe fn dc_e2ee_decrypt( 0 as *const libc::c_char, ); if !self_addr.is_null() { - if !(0 - == dc_keyring_load_self_private_for_decrypting( - context, - private_keyring, - self_addr, - &context.sql.clone().read().unwrap(), - )) - { - if (*peerstate).last_seen == 0i32 as libc::c_long { + if private_keyring.load_self_private_for_decrypting( + context, + self_addr, + &context.sql.clone().read().unwrap(), + ) { + if peerstate.last_seen == 0i32 as libc::c_long { dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), from, ); } - if 0 != (*peerstate).degrade_event { - dc_handle_degrade_event(context, peerstate); + if 0 != peerstate.degrade_event { + dc_handle_degrade_event(context, &peerstate); } - dc_keyring_add(public_keyring_for_validate, (*peerstate).gossip_key); - dc_keyring_add(public_keyring_for_validate, (*peerstate).public_key); + // TODO: avoid clone + public_keyring_for_validate.add(peerstate.gossip_key.clone().unwrap()); + public_keyring_for_validate.add(peerstate.public_key.clone().unwrap()); (*helper).signatures = malloc(::std::mem::size_of::()) as *mut dc_hash_t; dc_hash_init((*helper).signatures, 3i32, 1i32); iterations = 0i32; @@ -702,8 +683,8 @@ pub unsafe fn dc_e2ee_decrypt( if 0 == decrypt_recursive( context, in_out_message, - private_keyring, - public_keyring_for_validate, + &private_keyring, + &public_keyring_for_validate, (*helper).signatures, &mut gossip_headers, &mut has_unencrypted_parts, @@ -727,9 +708,7 @@ pub unsafe fn dc_e2ee_decrypt( mailimf_fields_free(gossip_headers); } - dc_apeerstate_unref(peerstate); - dc_keyring_unref(private_keyring); - dc_keyring_unref(public_keyring_for_validate); + dc_apeerstate_unref(&mut peerstate); free(from as *mut libc::c_void); free(self_addr as *mut libc::c_void); } @@ -765,63 +744,60 @@ unsafe fn update_gossip_peerstates( .unwrap(); let gossip_header = Aheader::from_str(value); if let Ok(ref header) = gossip_header { - if 0 != dc_pgp_is_valid_key(context, header.public_key) { - if recipients.is_null() { - recipients = mailimf_get_recipients(imffields) - } - if !dc_hash_find( - recipients, - CString::new(header.addr.clone()).unwrap().as_ptr() - as *const libc::c_void, - header.addr.len() as i32, - ) - .is_null() - { - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); - if 0 == dc_apeerstate_load_by_addr( - peerstate, + if recipients.is_null() { + recipients = mailimf_get_recipients(imffields) + } + if !dc_hash_find( + recipients, + CString::new(header.addr.clone()).unwrap().as_ptr() as *const libc::c_void, + header.addr.len() as i32, + ) + .is_null() + { + let mut peerstate = dc_apeerstate_new(context); + if 0 == dc_apeerstate_load_by_addr( + &mut peerstate, + &context.sql.clone().read().unwrap(), + CString::new(header.addr.clone()).unwrap().as_ptr(), + ) { + dc_apeerstate_init_from_gossip(&mut peerstate, header, message_time); + dc_apeerstate_save_to_db( + &mut peerstate, &context.sql.clone().read().unwrap(), - CString::new(header.addr.clone()).unwrap().as_ptr(), - ) { - dc_apeerstate_init_from_gossip(peerstate, header, message_time); - dc_apeerstate_save_to_db( - peerstate, - &context.sql.clone().read().unwrap(), - 1i32, - ); - } else { - dc_apeerstate_apply_gossip(peerstate, header, message_time); - dc_apeerstate_save_to_db( - peerstate, - &context.sql.clone().read().unwrap(), - 0i32, - ); - } - if 0 != (*peerstate).degrade_event { - dc_handle_degrade_event(context, peerstate); - } - dc_apeerstate_unref(peerstate); - if gossipped_addr.is_null() { - gossipped_addr = - malloc(::std::mem::size_of::()) as *mut dc_hash_t; - dc_hash_init(gossipped_addr, 3i32, 1i32); - } - dc_hash_insert( - gossipped_addr, - CString::new(header.addr.clone()).unwrap().as_ptr() - as *const libc::c_void, - header.addr.len() as libc::c_int, - 1i32 as *mut libc::c_void, + 1i32, ); } else { - dc_log_info( - context, + dc_apeerstate_apply_gossip(&mut peerstate, header, message_time); + dc_apeerstate_save_to_db( + &mut peerstate, + &context.sql.clone().read().unwrap(), 0i32, - b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00" - as *const u8 as *const libc::c_char, - CString::new(header.addr.clone()).unwrap().as_ptr(), ); } + if 0 != peerstate.degrade_event { + dc_handle_degrade_event(context, &peerstate); + } + dc_apeerstate_unref(&mut peerstate); + if gossipped_addr.is_null() { + gossipped_addr = + malloc(::std::mem::size_of::()) as *mut dc_hash_t; + dc_hash_init(gossipped_addr, 3i32, 1i32); + } + dc_hash_insert( + gossipped_addr, + CString::new(header.addr.clone()).unwrap().as_ptr() + as *const libc::c_void, + header.addr.len() as libc::c_int, + 1i32 as *mut libc::c_void, + ); + } else { + dc_log_info( + context, + 0i32, + b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00" + as *const u8 as *const libc::c_char, + CString::new(header.addr.clone()).unwrap().as_ptr(), + ); } } } @@ -844,8 +820,8 @@ unsafe fn update_gossip_peerstates( unsafe fn decrypt_recursive( context: &dc_context_t, mime: *mut mailmime, - private_keyring: *const dc_keyring_t, - public_keyring_for_validate: *const dc_keyring_t, + private_keyring: &Keyring, + public_keyring_for_validate: &Keyring, ret_valid_signatures: *mut dc_hash_t, ret_gossip_headers: *mut *mut mailimf_fields, ret_has_unencrypted_parts: *mut libc::c_int, @@ -949,10 +925,10 @@ unsafe fn decrypt_recursive( } unsafe fn decrypt_part( - context: &dc_context_t, + _context: &dc_context_t, mime: *mut mailmime, - private_keyring: *const dc_keyring_t, - public_keyring_for_validate: *const dc_keyring_t, + private_keyring: &Keyring, + public_keyring_for_validate: &Keyring, ret_valid_signatures: *mut dc_hash_t, ret_decrypted_mime: *mut *mut mailmime, ) -> libc::c_int { @@ -965,8 +941,6 @@ unsafe fn decrypt_part( /* must not be free()'d */ let mut decoded_data: *const libc::c_char = 0 as *const libc::c_char; let mut decoded_data_bytes: size_t = 0i32 as size_t; - let mut plain_buf: *mut libc::c_void = 0 as *mut libc::c_void; - let mut plain_bytes: size_t = 0i32 as size_t; let mut sth_decrypted: libc::c_int = 0i32; *ret_decrypted_mime = 0 as *mut mailmime; mime_data = (*mime).mm_data.mm_single; @@ -1044,22 +1018,18 @@ unsafe fn decrypt_part( 0 as *mut dc_hash_t }; /*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */ - if !(0 - == dc_pgp_pk_decrypt( - context, - decoded_data as *const libc::c_void, - decoded_data_bytes, - private_keyring, - public_keyring_for_validate, - 1i32, - &mut plain_buf, - &mut plain_bytes, - add_signatures, - ) - || plain_buf.is_null() - || plain_bytes <= 0) - { - //{char* t1=dc_null_terminate(plain_buf,plain_bytes);printf("\n**********\n%s\n**********\n",t1);free(t1);} + + if let Some(plain) = dc_pgp_pk_decrypt( + decoded_data as *const libc::c_void, + decoded_data_bytes, + &private_keyring, + &public_keyring_for_validate, + add_signatures, + ) { + let plain_bytes = plain.len(); + let plain_c = CString::new(plain).unwrap(); + let plain_buf = libc::strdup(plain_c.as_ptr()); + let mut index: size_t = 0i32 as size_t; let mut decrypted_mime: *mut mailmime = 0 as *mut mailmime; if mailmime_parse( @@ -1204,9 +1174,8 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &dc_context_t) -> libc::c_int /* normally, the key is generated as soon as the first mail is send (this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */ let mut success: libc::c_int = 0i32; - let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char; - self_addr = dc_sqlite3_get_config( + let self_addr = dc_sqlite3_get_config( context, &context.sql.clone().read().unwrap(), b"configured_addr\x00" as *const u8 as *const libc::c_char, diff --git a/src/dc_hash.rs b/src/dc_hash.rs index e63c94b7b..56bf92a70 100644 --- a/src/dc_hash.rs +++ b/src/dc_hash.rs @@ -121,28 +121,11 @@ pub unsafe fn dc_hash_insert( let mut new_elem: *mut dc_hashelem_t; /* The hash function */ let xHash: Option libc::c_int>; - if 0 != pH.is_null() as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 15], &[libc::c_char; 15]>(b"dc_hash_insert\x00")) - .as_ptr(), - b"../src/dc_hash.c\x00" as *const u8 as *const libc::c_char, - 429i32, - b"pH!=0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; + assert!(!pH.is_null()); xHash = hashFunction((*pH).keyClass as libc::c_int); - if 0 != xHash.is_none() as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 15], &[libc::c_char; 15]>(b"dc_hash_insert\x00")) - .as_ptr(), - b"../src/dc_hash.c\x00" as *const u8 as *const libc::c_char, - 431i32, - b"xHash!=0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; + assert!(xHash.is_some(), "missing hashing function"); hraw = xHash.expect("non-null function pointer")(pKey, nKey); + if 0 != !((*pH).htsize & (*pH).htsize - 1i32 == 0i32) as libc::c_int as libc::c_long { __assert_rtn( (*::std::mem::transmute::<&[u8; 15], &[libc::c_char; 15]>(b"dc_hash_insert\x00")) diff --git a/src/dc_imex.rs b/src/dc_imex.rs index 5dcfff805..31aa56410 100644 --- a/src/dc_imex.rs +++ b/src/dc_imex.rs @@ -1,3 +1,5 @@ +use std::ffi::{CStr, CString}; + use mmime::mailmime_content::*; use mmime::mmapstring::*; use mmime::other::*; @@ -290,7 +292,6 @@ pub unsafe extern "C" fn dc_render_setup_file( let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char; let mut passphrase_begin: [libc::c_char; 8] = [0; 8]; - let mut encr_string: *mut libc::c_char = 0 as *mut libc::c_char; let mut ret_setupfilecontent: *mut libc::c_char = 0 as *mut libc::c_char; if !(passphrase.is_null() || strlen(passphrase) < 2) { strncpy(passphrase_begin.as_mut_ptr(), passphrase, 2); @@ -319,22 +320,20 @@ pub unsafe extern "C" fn dc_render_setup_file( }; if let Some(payload_key_asc) = curr_private_key.map(|k| k.to_asc_c(headers)) { - if !(0 - == dc_pgp_symm_encrypt( - context, - passphrase, - payload_key_asc as *const libc::c_void, - strlen(payload_key_asc), - &mut encr_string, - )) - { + if let Some(encr) = dc_pgp_symm_encrypt( + passphrase, + payload_key_asc as *const libc::c_void, + strlen(payload_key_asc), + ) { + let encr_string = CString::new(encr).unwrap(); + free(payload_key_asc as *mut libc::c_void); let replacement: *mut libc::c_char = dc_mprintf(b"-----BEGIN PGP MESSAGE-----\r\nPassphrase-Format: numeric9x4\r\nPassphrase-Begin: %s\x00" as *const u8 as *const libc::c_char, passphrase_begin.as_mut_ptr()); dc_str_replace( - &mut encr_string, + &mut (encr_string.as_ptr() as *mut _), b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, replacement, ); @@ -355,7 +354,7 @@ pub unsafe extern "C" fn dc_render_setup_file( dc_mprintf(b"\r\n\r\n\r\n%s\r\n\r\n\r\n

%s

\r\n

%s

\r\n
\r\n%s\r\n
\r\n\r\n\r\n\x00" as *const u8 as *const libc::c_char, setup_message_title, setup_message_title, - setup_message_body, encr_string); + setup_message_body, encr_string.as_ptr()); free(setup_message_title as *mut libc::c_void); free(setup_message_body as *mut libc::c_void); } @@ -364,7 +363,6 @@ pub unsafe extern "C" fn dc_render_setup_file( } sqlite3_finalize(stmt); - free(encr_string as *mut libc::c_void); free(self_addr as *mut libc::c_void); ret_setupfilecontent @@ -519,8 +517,11 @@ unsafe fn set_self_key( b"File does not contain a private key.\x00" as *const u8 as *const libc::c_char, ); } else { - if let Some((private_key, public_key)) = Key::from_base64(buf_base64, KeyType::Private) - .and_then(|k| dc_pgp_split_key(context, &k).map(|pk| (k, pk))) + if let Some((private_key, public_key)) = Key::from_base64( + CStr::from_ptr(buf_base64).to_str().unwrap(), + KeyType::Private, + ) + .and_then(|k| k.split_key().map(|pub_key| (k, pub_key))) { stmt = dc_sqlite3_prepare( context, @@ -528,12 +529,20 @@ unsafe fn set_self_key( b"DELETE FROM keypairs WHERE public_key=? OR private_key=?;\x00" as *const u8 as *const libc::c_char, ); - sqlite3_bind_blob(stmt, 1i32, (*public_key).binary, (*public_key).bytes, None); + let bytes = public_key.to_bytes(); sqlite3_bind_blob( stmt, - 2i32, - (*private_key).binary, - (*private_key).bytes, + 1, + bytes.as_ptr() as *const _, + bytes.len() as libc::c_int, + None, + ); + let bytes = private_key.to_bytes(); + sqlite3_bind_blob( + stmt, + 2, + bytes.as_ptr() as *const _, + bytes.len() as libc::c_int, None, ); sqlite3_step(stmt); @@ -552,10 +561,10 @@ unsafe fn set_self_key( b"configured_addr\x00" as *const u8 as *const libc::c_char, 0 as *const libc::c_char, ); - if 0 == dc_key_save_self_keypair( + if !dc_key_save_self_keypair( context, - public_key, - private_key, + &public_key, + &private_key, self_addr, set_default, &context.sql.clone().read().unwrap(), @@ -611,7 +620,7 @@ unsafe fn set_self_key( } pub unsafe fn dc_decrypt_setup_file( - context: &dc_context_t, + _context: &dc_context_t, passphrase: *const libc::c_char, filecontent: *const libc::c_char, ) -> *mut libc::c_char { @@ -621,8 +630,7 @@ pub unsafe fn dc_decrypt_setup_file( let mut binary: *mut libc::c_char = 0 as *mut libc::c_char; let mut binary_bytes: size_t = 0i32 as size_t; let mut indx: size_t = 0i32 as size_t; - let mut plain: *mut libc::c_void = 0 as *mut libc::c_void; - let mut plain_bytes = 0; + let mut payload: *mut libc::c_char = 0 as *mut libc::c_char; fc_buf = dc_strdup(filecontent); if !(0 @@ -653,21 +661,14 @@ pub unsafe fn dc_decrypt_setup_file( || binary_bytes == 0) { /* decrypt symmetrically */ - if !(0 - == dc_pgp_symm_decrypt( - context, - passphrase, - binary as *const libc::c_void, - binary_bytes, - &mut plain, - &mut plain_bytes, - )) + if let Some(plain) = + dc_pgp_symm_decrypt(passphrase, binary as *const libc::c_void, binary_bytes) { - payload = strndup(plain as *const libc::c_char, plain_bytes as libc::c_ulong) + payload = libc::strdup(CString::new(plain).unwrap().as_ptr()); } } } - free(plain); + free(fc_buf as *mut libc::c_void); if !binary.is_null() { mmap_string_unref(binary); @@ -1582,15 +1583,23 @@ unsafe fn export_self_keys(context: &dc_context_t, dir: *const libc::c_char) -> if !stmt.is_null() { while sqlite3_step(stmt) == 100i32 { id = sqlite3_column_int(stmt, 0i32); - let public_key = Key::from_stmt(stmt, 1i32, KeyType::Public); - let private_key = Key::from_stmt(stmt, 2i32, KeyType::Private); + let public_key = Key::from_stmt(stmt, 1, KeyType::Public); + let private_key = Key::from_stmt(stmt, 2, KeyType::Private); is_default = sqlite3_column_int(stmt, 3i32); - if 0 == export_key_to_asc_file(context, dir, id, &public_key, is_default) { - export_errors += 1 + if let Some(key) = public_key { + if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) { + export_errors += 1 + } + } else { + export_errors += 1; } - if 0 == export_key_to_asc_file(context, dir, id, &private_key, is_default) { - export_errors += 1 + if let Some(key) = private_key { + if 0 == export_key_to_asc_file(context, dir, id, &key, is_default) { + export_errors += 1 + } + } else { + export_errors += 1; } } if export_errors == 0i32 { @@ -1619,7 +1628,7 @@ unsafe fn export_key_to_asc_file( file_name = dc_mprintf( b"%s/%s-key-default.asc\x00" as *const u8 as *const libc::c_char, dir, - if (*key).type_0 == 0i32 { + if key.is_public() { b"public\x00" as *const u8 as *const libc::c_char } else { b"private\x00" as *const u8 as *const libc::c_char @@ -1629,7 +1638,7 @@ unsafe fn export_key_to_asc_file( file_name = dc_mprintf( b"%s/%s-key-%i.asc\x00" as *const u8 as *const libc::c_char, dir, - if (*key).type_0 == 0i32 { + if key.is_public() { b"public\x00" as *const u8 as *const libc::c_char } else { b"private\x00" as *const u8 as *const libc::c_char diff --git a/src/dc_key.rs b/src/dc_key.rs index 674fc88d9..b3c96700e 100644 --- a/src/dc_key.rs +++ b/src/dc_key.rs @@ -4,21 +4,17 @@ use std::io::Cursor; use std::slice; use libc; -use mmime::mailmime_content::*; -use mmime::mmapstring::*; use mmime::other::*; use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey}; use pgp::ser::Serialize; +use pgp::types::{KeyTrait, SecretKeyTrait}; use crate::constants::*; use crate::dc_context::dc_context_t; use crate::dc_log::*; -use crate::dc_pgp::*; use crate::dc_sqlite3::*; -use crate::dc_strbuilder::*; use crate::dc_tools::*; use crate::types::*; -use crate::x::*; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Key { @@ -26,6 +22,62 @@ pub enum Key { Secret(SignedSecretKey), } +impl From for Key { + fn from(key: SignedPublicKey) -> Self { + Key::Public(key) + } +} + +impl From for Key { + fn from(key: SignedSecretKey) -> Self { + Key::Secret(key) + } +} + +impl std::convert::TryInto for Key { + type Error = (); + + fn try_into(self) -> Result { + match self { + Key::Public(_) => Err(()), + Key::Secret(key) => Ok(key), + } + } +} + +impl<'a> std::convert::TryInto<&'a SignedSecretKey> for &'a Key { + type Error = (); + + fn try_into(self) -> Result<&'a SignedSecretKey, Self::Error> { + match self { + Key::Public(_) => Err(()), + Key::Secret(key) => Ok(key), + } + } +} + +impl std::convert::TryInto for Key { + type Error = (); + + fn try_into(self) -> Result { + match self { + Key::Public(key) => Ok(key), + Key::Secret(_) => Err(()), + } + } +} + +impl<'a> std::convert::TryInto<&'a SignedPublicKey> for &'a Key { + type Error = (); + + fn try_into(self) -> Result<&'a SignedPublicKey, Self::Error> { + match self { + Key::Public(key) => Ok(key), + Key::Secret(_) => Err(()), + } + } +} + impl Key { pub fn is_public(&self) -> bool { match self { @@ -41,10 +93,10 @@ impl Key { pub fn from_slice(bytes: &[u8], key_type: KeyType) -> Option { match key_type { KeyType::Public => SignedPublicKey::from_bytes(Cursor::new(bytes)) - .map(|k| Key::Public(k)) + .map(Into::into) .ok(), - KeyType::Secret => SignedSecretKey::from_bytes(Cursor::new(bytes)) - .map(|k| Key::Secret(k)) + KeyType::Private => SignedSecretKey::from_bytes(Cursor::new(bytes)) + .map(Into::into) .ok(), } } @@ -57,7 +109,7 @@ impl Key { assert!(!data.is_null(), "missing data"); assert!(len > 0); - let bytes = unsafe { slice::from_raw_parts(data, len) }; + let bytes = unsafe { slice::from_raw_parts(data as *const u8, len as usize) }; Self::from_slice(bytes, key_type) } @@ -77,8 +129,9 @@ impl Key { } pub fn from_base64(encoded_data: &str, key_type: KeyType) -> Option { - // TODO: strip newlines and other whitespace - let bytes = encoded_data.as_bytes(); + // strip newlines and other whitespace + let cleaned: String = encoded_data.trim().split_whitespace().collect(); + let bytes = cleaned.as_bytes(); base64::decode(bytes) .ok() @@ -94,21 +147,23 @@ impl Key { return None; } - let stmt = dc_sqlite3_prepare( - context, - sql, - b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8 - as *const libc::c_char, - ); - sqlite3_bind_text(stmt, 1, self_addr, -1, None); + let stmt = unsafe { + dc_sqlite3_prepare( + context, + sql, + b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8 + as *const libc::c_char, + ) + }; + unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) }; - let key = if sqlite3_step(stmt) == 100 { - Self::from_stmt(stmt, 0, KeyType::Public); + let key = if unsafe { sqlite3_step(stmt) } == 100 { + Self::from_stmt(stmt, 0, KeyType::Public) } else { None }; - sqlite3_finalize(stmt); + unsafe { sqlite3_finalize(stmt) }; key } @@ -122,26 +177,35 @@ impl Key { return None; } - let stmt = dc_sqlite3_prepare( - context, - sql, - b"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8 - as *const libc::c_char, - ); - sqlite3_bind_text(stmt, 1, self_addr, -1, None); + let stmt = unsafe { + dc_sqlite3_prepare( + context, + sql, + b"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8 + as *const libc::c_char, + ) + }; + unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) }; - let key = if sqlite3_step(stmt) == 100 { - Self::from_stmt(stmt, 0, KeyType::Secret) + let key = if unsafe { sqlite3_step(stmt) } == 100 { + Self::from_stmt(stmt, 0, KeyType::Private) } else { None }; - sqlite3_finalize(stmt); + unsafe { sqlite3_finalize(stmt) }; key } + pub fn to_bytes(&self) -> Vec { + match self { + Key::Public(k) => k.to_bytes().unwrap(), + Key::Secret(k) => k.to_bytes().unwrap(), + } + } + pub fn to_base64(&self, break_every: usize) -> String { - let buf = self.0.to_bytes().expect("failed to serialize key"); + let buf = self.to_bytes(); let encoded = base64::encode(&buf); encoded @@ -167,6 +231,16 @@ impl Key { unsafe { libc::strdup(res_c.as_ptr()) } } + pub fn to_armored_string( + &self, + headers: Option<&BTreeMap>, + ) -> pgp::errors::Result { + match self { + Key::Public(k) => k.to_armored_string(headers), + Key::Secret(k) => k.to_armored_string(headers), + } + } + /// Each header line must be terminated by `\r\n`, the result must be freed. pub fn to_asc_c(&self, header: Option<(&str, &str)>) -> *mut libc::c_char { let headers = header.map(|(key, value)| { @@ -176,7 +250,6 @@ impl Key { }); let buf = self - .0 .to_armored_string(headers.as_ref()) .expect("failed to serialize key"); let buf_c = CString::new(buf).unwrap(); @@ -191,7 +264,7 @@ impl Key { return false; } - let file_content = self.to_asc(None); + let file_content = self.to_asc_c(None); let success = if 0 == unsafe { @@ -208,13 +281,16 @@ impl Key { true }; - free(file_content as *mut libc::c_void); + unsafe { free(file_content as *mut libc::c_void) }; success } pub fn fingerprint(&self) -> String { - hex::encode_upper(self.0.fingerprint()) + match self { + Key::Public(k) => hex::encode_upper(k.fingerprint()), + Key::Secret(k) => hex::encode_upper(k.fingerprint()), + } } pub fn fingerprint_c(&self) -> *mut libc::c_char { @@ -228,11 +304,21 @@ impl Key { dc_format_fingerprint(&rawhex) } - pub fn formatted_fingerprint_c(&self) -> String { + pub fn formatted_fingerprint_c(&self) -> *mut libc::c_char { let res = CString::new(self.formatted_fingerprint()).unwrap(); unsafe { libc::strdup(res.as_ptr()) } } + + pub fn split_key(&self) -> Option { + match self { + Key::Public(_) => None, + Key::Secret(k) => { + let pub_key = k.public_key(); + pub_key.sign(k, || "".into()).map(|k| Key::Public(k)).ok() + } + } + } } pub fn dc_key_save_self_keypair( @@ -244,30 +330,50 @@ pub fn dc_key_save_self_keypair( sql: &dc_sqlite3_t, ) -> bool { if addr.is_null() { - return 0; + return false; } - let stmt = dc_sqlite3_prepare( + let stmt = unsafe { + dc_sqlite3_prepare( context, sql, b"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);\x00" as *const u8 as *const libc::c_char - ); + ) + }; - sqlite3_bind_text(stmt, 1, addr, -1, None); - sqlite3_bind_int(stmt, 2, is_default); + unsafe { + sqlite3_bind_text(stmt, 1, addr, -1, None); + sqlite3_bind_int(stmt, 2, is_default) + }; let pub_bytes = public_key.to_bytes(); let sec_bytes = private_key.to_bytes(); - sqlite3_bind_blob(stmt, 3, pub_bytes.as_ptr(), pub_bytes.len(), None); - sqlite3_bind_blob(stmt, 4, sec_bytes.as_ptr(), sec_bytes.len(), None); - sqlite3_bind_int64(stmt, 5, time(0 as *mut time_t) as sqlite3_int64); - let success = if sqlite3_step(stmt) == 101 { + unsafe { + sqlite3_bind_blob( + stmt, + 3, + pub_bytes.as_ptr() as *const _, + pub_bytes.len() as libc::c_int, + None, + ) + }; + unsafe { + sqlite3_bind_blob( + stmt, + 4, + sec_bytes.as_ptr() as *const _, + sec_bytes.len() as libc::c_int, + None, + ) + }; + unsafe { sqlite3_bind_int64(stmt, 5, time(0 as *mut time_t) as sqlite3_int64) }; + let success = if unsafe { sqlite3_step(stmt) } == 101 { true } else { false }; - sqlite3_finalize(stmt); + unsafe { sqlite3_finalize(stmt) }; success } @@ -275,20 +381,43 @@ pub fn dc_key_save_self_keypair( /// Make a fingerprint human-readable, in hex format. pub fn dc_format_fingerprint(fingerprint: &str) -> String { // split key into chunks of 4 with space, and 20 newline - fingerprint - .as_bytes() - .chunks(4) - .chunks(5) - .map(|chunk| chunk.join(" ")) - .join("\n") + let mut res = String::new(); + + for (i, c) in fingerprint.chars().enumerate() { + if i > 0 && i % 20 == 0 { + res += "\n"; + } else if i > 0 && i % 4 == 0 { + res += " "; + } + + res += &c.to_string(); + } + + res +} + +pub fn dc_format_fingerprint_c(fp: *const libc::c_char) -> *mut libc::c_char { + let input = unsafe { CStr::from_ptr(fp).to_str().unwrap() }; + let res = dc_format_fingerprint(input); + let res_c = CString::new(res).unwrap(); + + unsafe { libc::strdup(res_c.as_ptr()) } } /// Bring a human-readable or otherwise formatted fingerprint back to the 40-characters-uppercase-hex format. -pub unsafe fn dc_normalize_fingerprint(fp: &str) -> String { +pub fn dc_normalize_fingerprint(fp: &str) -> String { fp.to_uppercase() .chars() - .filter(|c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') - .join("") + .filter(|&c| c >= '0' && c <= '9' || c >= 'A' && c <= 'F') + .collect() +} + +pub fn dc_normalize_fingerprint_c(fp: *const libc::c_char) -> *mut libc::c_char { + let input = unsafe { CStr::from_ptr(fp).to_str().unwrap() }; + let res = dc_normalize_fingerprint(input); + let res_c = CString::new(res).unwrap(); + + unsafe { libc::strdup(res_c.as_ptr()) } } #[cfg(test)] @@ -304,12 +433,11 @@ mod tests { #[test] fn test_format_fingerprint() { - let fingerprint = dc_normalize_fingerprint("1234567890ABCDABCDEFABCDEF1234567890ABCD"); + let fingerprint = dc_format_fingerprint("1234567890ABCDABCDEFABCDEF1234567890ABCD"); assert_eq!( fingerprint, "1234 5678 90AB CDAB CDEF\nABCD EF12 3456 7890 ABCD" ); } - } diff --git a/src/dc_keyring.rs b/src/dc_keyring.rs index a9aad8ba8..1901e53d1 100644 --- a/src/dc_keyring.rs +++ b/src/dc_keyring.rs @@ -1,18 +1,23 @@ +use crate::constants::*; use crate::dc_context::dc_context_t; use crate::dc_key::*; use crate::dc_sqlite3::*; use crate::types::*; #[derive(Default, Clone, Debug)] -pub struct dc_keyring_t { +pub struct Keyring { keys: Vec, } -impl dc_keyring_t { +impl Keyring { pub fn add(&mut self, key: Key) { self.keys.push(key); } + pub fn keys(&self) -> &[Key] { + &self.keys + } + pub fn load_self_private_for_decrypting( &mut self, context: &dc_context_t, @@ -23,19 +28,21 @@ impl dc_keyring_t { if self_addr.is_null() { return false; } - let stmt = dc_sqlite3_prepare( - context, - sql, - b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00" - as *const u8 as *const libc::c_char, - ); - sqlite3_bind_text(stmt, 1, self_addr, -1, None); - while sqlite3_step(stmt) == 100 { - if let Some(key) = Key::from_stmt(stmt, 0, 1) { + let stmt = unsafe { + dc_sqlite3_prepare( + context, + sql, + b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00" + as *const u8 as *const libc::c_char, + ) + }; + unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) }; + while unsafe { sqlite3_step(stmt) == 100 } { + if let Some(key) = Key::from_stmt(stmt, 0, KeyType::Private) { self.add(key); } } - sqlite3_finalize(stmt); + unsafe { sqlite3_finalize(stmt) }; true } diff --git a/src/dc_pgp.rs b/src/dc_pgp.rs index 082cb4541..ea17b0bda 100644 --- a/src/dc_pgp.rs +++ b/src/dc_pgp.rs @@ -1,15 +1,23 @@ -use crate::dc_context::dc_context_t; +use std::convert::TryInto; +use std::ffi::{CStr, CString}; +use std::io::Cursor; + +use pgp::composed::{ + Deserializable, KeyType as PgpKeyType, Message, SecretKeyParamsBuilder, SignedPublicKey, + SignedSecretKey, SubkeyParamsBuilder, +}; +use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm}; +use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait, StringToKey}; +use rand::thread_rng; +use sha2::{Digest, Sha256}; + use crate::dc_hash::*; use crate::dc_key::*; use crate::dc_keyring::*; -use crate::dc_log::*; use crate::dc_tools::*; -use crate::pgp as rpgp; use crate::types::*; use crate::x::*; -pub unsafe fn dc_pgp_exit() {} - // TODO should return bool /rtn pub unsafe fn dc_split_armored_data( buf: *mut libc::c_char, @@ -129,613 +137,212 @@ pub unsafe fn dc_split_armored_data( success } -/* public key encryption */ -// TODO should return bool /rtn -pub unsafe fn dc_pgp_create_keypair( - context: &dc_context_t, - addr: *const libc::c_char, - ret_public_key: *mut dc_key_t, - ret_private_key: *mut dc_key_t, -) -> libc::c_int { - let mut success: libc::c_int = 0i32; - let skey: *mut rpgp::signed_secret_key; - let mut pkey: *mut rpgp::signed_public_key = 0 as *mut rpgp::signed_public_key; - let mut skey_bytes: *mut rpgp::cvec = 0 as *mut rpgp::cvec; - let mut pkey_bytes: *mut rpgp::cvec = 0 as *mut rpgp::cvec; - let user_id: *mut libc::c_char; - user_id = dc_mprintf(b"<%s>\x00" as *const u8 as *const libc::c_char, addr); - skey = rpgp::rpgp_create_rsa_skey(2048i32 as uint32_t, user_id); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - skey_bytes = rpgp::rpgp_skey_to_bytes(skey); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - pkey = rpgp::rpgp_skey_public_key(skey); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - pkey_bytes = rpgp::rpgp_pkey_to_bytes(pkey); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - dc_key_set_from_binary( - ret_private_key, - rpgp::rpgp_cvec_data(skey_bytes) as *const libc::c_void, - rpgp::rpgp_cvec_len(skey_bytes) as libc::c_int, - 1i32, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - dc_key_set_from_binary( - ret_public_key, - rpgp::rpgp_cvec_data(pkey_bytes) as *const libc::c_void, - rpgp::rpgp_cvec_len(pkey_bytes) as libc::c_int, - 0i32, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - success = 1i32 - } - } - } - } - } - } - /* cleanup */ - if !skey.is_null() { - rpgp::rpgp_skey_drop(skey); - } - if !skey_bytes.is_null() { - rpgp::rpgp_cvec_drop(skey_bytes); - } - if !pkey.is_null() { - rpgp::rpgp_pkey_drop(pkey); - } - if !pkey_bytes.is_null() { - rpgp::rpgp_cvec_drop(pkey_bytes); - } - if !user_id.is_null() { - free(user_id as *mut libc::c_void); - } +/// Create a new key pair. +pub fn dc_pgp_create_keypair(addr: *const libc::c_char) -> Option<(Key, Key)> { + let user_id = format!("<{}>", unsafe { CStr::from_ptr(addr).to_str().unwrap() }); - success + let key_params = SecretKeyParamsBuilder::default() + .key_type(PgpKeyType::Rsa(2048)) + .can_create_certificates(true) + .can_sign(true) + .primary_user_id(user_id.into()) + .passphrase(None) + .preferred_symmetric_algorithms(smallvec![ + SymmetricKeyAlgorithm::AES256, + SymmetricKeyAlgorithm::AES192, + SymmetricKeyAlgorithm::AES128, + ]) + .preferred_hash_algorithms(smallvec![ + HashAlgorithm::SHA2_256, + HashAlgorithm::SHA2_384, + HashAlgorithm::SHA2_512, + HashAlgorithm::SHA2_224, + HashAlgorithm::SHA1, + ]) + .preferred_compression_algorithms(smallvec![ + CompressionAlgorithm::ZLIB, + CompressionAlgorithm::ZIP, + ]) + .subkey( + SubkeyParamsBuilder::default() + .key_type(PgpKeyType::Rsa(2048)) + .can_encrypt(true) + .passphrase(None) + .build() + .unwrap(), + ) + .build() + .expect("invalid key params"); + + let key = key_params.generate().expect("invalid params"); + let private_key = key.sign(|| "".into()).expect("failed to sign secret key"); + + let public_key = private_key.public_key(); + let public_key = public_key + .sign(&private_key, || "".into()) + .expect("failed to sign public key"); + + Some((Key::Public(public_key), Key::Secret(private_key))) } -/* returns 0 if there is no error, otherwise logs the error if a context is provided and returns 1*/ -// TODO should return bool /rtn -pub unsafe fn dc_pgp_handle_rpgp_error(context: &dc_context_t) -> libc::c_int { - let mut success: libc::c_int = 0i32; - let len: libc::c_int; - let mut msg: *mut libc::c_char = 0 as *mut libc::c_char; - len = rpgp::rpgp_last_error_length(); - if !(len == 0i32) { - msg = rpgp::rpgp_last_error_message(); - dc_log_info( - context, - 0i32, - b"[rpgp][error] %s\x00" as *const u8 as *const libc::c_char, - msg, - ); - success = 1i32 - } - if !msg.is_null() { - rpgp::rpgp_string_drop(msg); - } - - success -} - -// TODO should return bool /rtn -pub unsafe fn dc_pgp_is_valid_key(context: &dc_context_t, raw_key: *const dc_key_t) -> libc::c_int { - let mut key_is_valid: libc::c_int = 0i32; - let mut key: *mut rpgp::public_or_secret_key = 0 as *mut rpgp::public_or_secret_key; - if !(raw_key.is_null() || (*raw_key).binary.is_null() || (*raw_key).bytes <= 0i32) { - key = rpgp::rpgp_key_from_bytes( - (*raw_key).binary as *const uint8_t, - (*raw_key).bytes as usize, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - if (*raw_key).type_0 == 0i32 && 0 != rpgp::rpgp_key_is_public(key) as libc::c_int { - key_is_valid = 1i32 - } else if (*raw_key).type_0 == 1i32 && 0 != rpgp::rpgp_key_is_secret(key) as libc::c_int - { - key_is_valid = 1i32 - } - } - } - if !key.is_null() { - rpgp::rpgp_key_drop(key); - } - - key_is_valid -} - -// TODO should return bool /rtn -pub unsafe fn dc_pgp_calc_fingerprint( - context: &dc_context_t, - raw_key: *const dc_key_t, - ret_fingerprint: *mut *mut uint8_t, - ret_fingerprint_bytes: *mut size_t, -) -> libc::c_int { - let mut success: libc::c_int = 0i32; - let mut key: *mut rpgp::public_or_secret_key = 0 as *mut rpgp::public_or_secret_key; - let mut fingerprint: *mut rpgp::cvec = 0 as *mut rpgp::cvec; - if !(raw_key.is_null() - || ret_fingerprint.is_null() - || !(*ret_fingerprint).is_null() - || ret_fingerprint_bytes.is_null() - || *ret_fingerprint_bytes != 0 - || (*raw_key).binary.is_null() - || (*raw_key).bytes <= 0i32) - { - key = rpgp::rpgp_key_from_bytes( - (*raw_key).binary as *const uint8_t, - (*raw_key).bytes as usize, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - fingerprint = rpgp::rpgp_key_fingerprint(key); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - *ret_fingerprint_bytes = rpgp::rpgp_cvec_len(fingerprint) as size_t; - *ret_fingerprint = malloc(*ret_fingerprint_bytes) as *mut uint8_t; - memcpy( - *ret_fingerprint as *mut libc::c_void, - rpgp::rpgp_cvec_data(fingerprint) as *const libc::c_void, - *ret_fingerprint_bytes, - ); - success = 1i32 - } - } - } - if !key.is_null() { - rpgp::rpgp_key_drop(key); - } - if !fingerprint.is_null() { - rpgp::rpgp_cvec_drop(fingerprint); - } - - success -} - -// TODO should return bool /rtn -pub unsafe fn dc_pgp_split_key(context: &dc_context_t, private_in: *const dc_key_t) -> Option { - let mut success: libc::c_int = 0i32; - let mut key: *mut rpgp::signed_secret_key = 0 as *mut rpgp::signed_secret_key; - let mut pub_key: *mut rpgp::signed_public_key = 0 as *mut rpgp::signed_public_key; - let mut buf: *mut rpgp::cvec = 0 as *mut rpgp::cvec; - if !(private_in.is_null() || ret_public_key.is_null()) { - if (*private_in).type_0 != 1i32 { - dc_log_warning( - context, - 0i32, - b"Split key: Given key is no private key.\x00" as *const u8 as *const libc::c_char, - ); - } else { - key = rpgp::rpgp_skey_from_bytes( - (*private_in).binary as *const uint8_t, - (*private_in).bytes as usize, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - pub_key = rpgp::rpgp_skey_public_key(key); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - buf = rpgp::rpgp_pkey_to_bytes(pub_key); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - dc_key_set_from_binary( - ret_public_key, - rpgp::rpgp_cvec_data(buf) as *const libc::c_void, - rpgp::rpgp_cvec_len(buf) as libc::c_int, - 0i32, - ); - success = 1i32 - } - } - } - } - } - if !key.is_null() { - rpgp::rpgp_skey_drop(key); - } - if !pub_key.is_null() { - rpgp::rpgp_pkey_drop(pub_key); - } - if !buf.is_null() { - rpgp::rpgp_cvec_drop(buf); - } - - success -} - -// TODO should return bool /rtn -pub unsafe fn dc_pgp_pk_encrypt( - context: &dc_context_t, +pub fn dc_pgp_pk_encrypt( plain_text: *const libc::c_void, plain_bytes: size_t, - raw_public_keys_for_encryption: *const dc_keyring_t, - raw_private_key_for_signing: *const dc_key_t, - use_armor: libc::c_int, - ret_ctext: *mut *mut libc::c_void, - ret_ctext_bytes: *mut size_t, -) -> libc::c_int { - let mut current_block: u64; - let mut i: libc::c_int; - let mut success: libc::c_int = 0i32; - let mut public_keys_len: libc::c_int = 0i32; - let mut public_keys: *mut *mut rpgp::signed_public_key = 0 as *mut *mut rpgp::signed_public_key; - let mut private_key: *mut rpgp::signed_secret_key = 0 as *mut rpgp::signed_secret_key; - let mut encrypted: *mut rpgp::Message = 0 as *mut rpgp::Message; - if !(plain_text == 0 as *mut libc::c_void - || plain_bytes == 0 - || ret_ctext.is_null() - || ret_ctext_bytes.is_null() - || raw_public_keys_for_encryption.is_null() - || (*raw_public_keys_for_encryption).count <= 0i32 - || use_armor == 0i32) - { - /* only support use_armor=1 */ - *ret_ctext = 0 as *mut libc::c_void; - *ret_ctext_bytes = 0i32 as size_t; - public_keys_len = (*raw_public_keys_for_encryption).count; - public_keys = malloc( - (::std::mem::size_of::<*mut rpgp::signed_public_key>()) - .wrapping_mul(public_keys_len as usize), - ) as *mut *mut rpgp::signed_public_key; - /* setup secret key for signing */ - if !raw_private_key_for_signing.is_null() { - private_key = rpgp::rpgp_skey_from_bytes( - (*raw_private_key_for_signing).binary as *const uint8_t, - (*raw_private_key_for_signing).bytes as usize, - ); - if private_key.is_null() || 0 != dc_pgp_handle_rpgp_error(context) { - dc_log_warning( - context, - 0i32, - b"No key for signing found.\x00" as *const u8 as *const libc::c_char, - ); - current_block = 2132137392766895896; - } else { - current_block = 12800627514080957624; - } - } else { - current_block = 12800627514080957624; - } - match current_block { - 2132137392766895896 => {} - _ => { - /* setup public keys for encryption */ - i = 0i32; - loop { - if !(i < public_keys_len) { - current_block = 6057473163062296781; - break; - } - let ref mut fresh0 = *public_keys.offset(i as isize); - *fresh0 = rpgp::rpgp_pkey_from_bytes( - (**(*raw_public_keys_for_encryption).keys.offset(i as isize)).binary - as *const uint8_t, - (**(*raw_public_keys_for_encryption).keys.offset(i as isize)).bytes - as usize, - ); - if 0 != dc_pgp_handle_rpgp_error(context) { - current_block = 2132137392766895896; - break; - } - i += 1 - } - match current_block { - 2132137392766895896 => {} - _ => { - /* sign & encrypt */ - let op_clocks: libc::clock_t; - let start: libc::clock_t = clock(); - if private_key.is_null() { - encrypted = rpgp::rpgp_encrypt_bytes_to_keys( - plain_text as *const uint8_t, - plain_bytes as usize, - public_keys as *const *const rpgp::signed_public_key, - public_keys_len as usize, - ); - if 0 != dc_pgp_handle_rpgp_error(context) { - dc_log_warning( - context, - 0i32, - b"Encryption failed.\x00" as *const u8 as *const libc::c_char, - ); - current_block = 2132137392766895896; - } else { - op_clocks = clock().wrapping_sub(start); - dc_log_info( - context, - 0i32, - b"Message encrypted in %.3f ms.\x00" as *const u8 - as *const libc::c_char, - op_clocks as libc::c_double * 1000.0f64 - / 1000000i32 as libc::c_double, - ); - current_block = 1538046216550696469; - } - } else { - encrypted = rpgp::rpgp_sign_encrypt_bytes_to_keys( - plain_text as *const uint8_t, - plain_bytes as usize, - public_keys as *const *const rpgp::signed_public_key, - public_keys_len as usize, - private_key, - ); - if 0 != dc_pgp_handle_rpgp_error(context) { - dc_log_warning( - context, - 0i32, - b"Signing and encrypting failed.\x00" as *const u8 - as *const libc::c_char, - ); - current_block = 2132137392766895896; - } else { - op_clocks = clock().wrapping_sub(start); - dc_log_info( - context, - 0i32, - b"Message signed and encrypted in %.3f ms.\x00" as *const u8 - as *const libc::c_char, - op_clocks as libc::c_double * 1000.0f64 - / 1000000i32 as libc::c_double, - ); - current_block = 1538046216550696469; - } - } - match current_block { - 2132137392766895896 => {} - _ => { - /* convert message to armored bytes and return values */ - let armored: *mut rpgp::cvec = rpgp::rpgp_msg_to_armored(encrypted); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - *ret_ctext = rpgp::rpgp_cvec_data(armored) as *mut libc::c_void; - *ret_ctext_bytes = rpgp::rpgp_cvec_len(armored) as size_t; - free(armored as *mut libc::c_void); - success = 1i32 - } - } - } - } - } - } - } - } - if !private_key.is_null() { - rpgp::rpgp_skey_drop(private_key); - } - i = 0i32; - while i < public_keys_len { - rpgp::rpgp_pkey_drop(*public_keys.offset(i as isize)); - i += 1 - } - if !encrypted.is_null() { - rpgp::rpgp_msg_drop(encrypted); - } + public_keys_for_encryption: &Keyring, + private_key_for_signing: Option<&Key>, +) -> Option { + assert!(!plain_text.is_null() && !plain_bytes > 0, "invalid input"); - success + let bytes = unsafe { std::slice::from_raw_parts(plain_text as *const u8, plain_bytes) }; + let lit_msg = Message::new_literal_bytes("", bytes); + let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption + .keys() + .iter() + .filter_map(|key| key.try_into().ok()) + .collect(); + + let mut rng = thread_rng(); + + // TODO: measure time + // TODO: better error handling + let encrypted_msg = if let Some(private_key) = private_key_for_signing { + let skey: &SignedSecretKey = private_key.try_into().unwrap(); + + lit_msg + .sign(skey, || "".into(), Default::default()) + .and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB)) + .and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys)) + } else { + lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys) + }; + + encrypted_msg + .and_then(|msg| msg.to_armored_string(None)) + .ok() } -// TODO should return bool /rtn -pub unsafe fn dc_pgp_pk_decrypt( - context: &dc_context_t, +pub fn dc_pgp_pk_decrypt( ctext: *const libc::c_void, ctext_bytes: size_t, - raw_private_keys_for_decryption: *const dc_keyring_t, - raw_public_keys_for_validation: *const dc_keyring_t, - use_armor: libc::c_int, - ret_plain: *mut *mut libc::c_void, - ret_plain_bytes: *mut size_t, + private_keys_for_decryption: &Keyring, + public_keys_for_validation: &Keyring, ret_signature_fingerprints: *mut dc_hash_t, -) -> libc::c_int { - let mut current_block: u64; - let mut i: libc::c_int; - let mut success: libc::c_int = 0i32; - let mut encrypted: *mut rpgp::Message = 0 as *mut rpgp::Message; - let mut decrypted: *mut rpgp::message_decrypt_result = 0 as *mut rpgp::message_decrypt_result; - let mut private_keys_len: libc::c_int = 0i32; - let mut public_keys_len: libc::c_int = 0i32; - let mut private_keys: *mut *mut rpgp::signed_secret_key = - 0 as *mut *mut rpgp::signed_secret_key; - let mut public_keys: *mut *mut rpgp::signed_public_key = 0 as *mut *mut rpgp::signed_public_key; - if !(ctext == 0 as *mut libc::c_void - || ctext_bytes == 0 - || ret_plain.is_null() - || ret_plain_bytes.is_null() - || raw_private_keys_for_decryption.is_null() - || (*raw_private_keys_for_decryption).count <= 0i32 - || use_armor == 0i32) - { - /* only support use_armor=1 */ - *ret_plain = 0 as *mut libc::c_void; - *ret_plain_bytes = 0i32 as size_t; - private_keys_len = (*raw_private_keys_for_decryption).count; - private_keys = malloc( - (::std::mem::size_of::<*mut rpgp::signed_secret_key>()) - .wrapping_mul(private_keys_len as usize), - ) as *mut *mut rpgp::signed_secret_key; - if !raw_public_keys_for_validation.is_null() { - public_keys_len = (*raw_public_keys_for_validation).count; - public_keys = malloc( - (::std::mem::size_of::<*mut rpgp::signed_public_key>()) - .wrapping_mul(public_keys_len as usize), - ) as *mut *mut rpgp::signed_public_key - } - /* setup secret keys for decryption */ - i = 0i32; - loop { - if !(i < (*raw_private_keys_for_decryption).count) { - current_block = 15904375183555213903; - break; - } - let ref mut fresh1 = *private_keys.offset(i as isize); - *fresh1 = rpgp::rpgp_skey_from_bytes( - (**(*raw_private_keys_for_decryption).keys.offset(i as isize)).binary - as *const uint8_t, - (**(*raw_private_keys_for_decryption).keys.offset(i as isize)).bytes as usize, - ); - if 0 != dc_pgp_handle_rpgp_error(context) { - current_block = 11904635156640512504; - break; - } - i += 1 - } - match current_block { - 11904635156640512504 => {} - _ => { - /* setup public keys for validation */ - if !raw_public_keys_for_validation.is_null() { - i = 0i32; - loop { - if !(i < (*raw_public_keys_for_validation).count) { - current_block = 7172762164747879670; - break; - } - let ref mut fresh2 = *public_keys.offset(i as isize); - *fresh2 = rpgp::rpgp_pkey_from_bytes( - (**(*raw_public_keys_for_validation).keys.offset(i as isize)).binary - as *const uint8_t, - (**(*raw_public_keys_for_validation).keys.offset(i as isize)).bytes - as usize, - ); - if 0 != dc_pgp_handle_rpgp_error(context) { - current_block = 11904635156640512504; - break; - } - i += 1 - } - } else { - current_block = 7172762164747879670; - } - match current_block { - 11904635156640512504 => {} - _ => { - /* decrypt */ - encrypted = rpgp::rpgp_msg_from_armor( - ctext as *const uint8_t, - ctext_bytes as usize, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - decrypted = rpgp::rpgp_msg_decrypt_no_pw( - encrypted, - private_keys as *const *const rpgp::signed_secret_key, - private_keys_len as usize, - public_keys as *const *const rpgp::signed_public_key, - public_keys_len as usize, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - let decrypted_bytes: *mut rpgp::cvec = - rpgp::rpgp_msg_to_bytes((*decrypted).message_ptr); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - *ret_plain_bytes = - rpgp::rpgp_cvec_len(decrypted_bytes) as size_t; - *ret_plain = - rpgp::rpgp_cvec_data(decrypted_bytes) as *mut libc::c_void; - free(decrypted_bytes as *mut libc::c_void); - if !ret_signature_fingerprints.is_null() { - let mut j: uint32_t = 0i32 as uint32_t; - let len: uint32_t = (*decrypted).valid_ids_len as uint32_t; - while j < len { - let fingerprint_hex: *mut libc::c_char = - *(*decrypted).valid_ids_ptr.offset(j as isize); - if !fingerprint_hex.is_null() { - dc_hash_insert( - ret_signature_fingerprints, - fingerprint_hex as *const libc::c_void, - strlen(fingerprint_hex) as libc::c_int, - 1i32 as *mut libc::c_void, - ); - free(fingerprint_hex as *mut libc::c_void); - } - j = j.wrapping_add(1) - } - } - success = 1i32 - } - } - } - } - } - } - } - } - i = 0i32; - while i < private_keys_len { - rpgp::rpgp_skey_drop(*private_keys.offset(i as isize)); - i += 1 - } - i = 0i32; - while i < public_keys_len { - rpgp::rpgp_pkey_drop(*public_keys.offset(i as isize)); - i += 1 - } - if !encrypted.is_null() { - rpgp::rpgp_msg_drop(encrypted); - } - if !decrypted.is_null() { - rpgp::rpgp_message_decrypt_result_drop(decrypted); - } +) -> Option> { + assert!(!ctext.is_null() && ctext_bytes > 0, "invalid input"); - success + let ctext = unsafe { std::slice::from_raw_parts(ctext as *const u8, ctext_bytes) }; + + // TODO: proper error handling + if let Ok((msg, _)) = Message::from_armor_single(Cursor::new(ctext)) { + let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption + .keys() + .iter() + .filter_map(|key| key.try_into().ok()) + .collect(); + + msg.decrypt(|| "".into(), || "".into(), &skeys[..]) + .and_then(|(mut decryptor, _)| { + // TODO: how to handle the case when we detect multiple messages? + decryptor.next().expect("no message") + }) + .and_then(|dec_msg| { + if !ret_signature_fingerprints.is_null() + && !public_keys_for_validation.keys().is_empty() + { + let pkeys: Vec<&SignedPublicKey> = public_keys_for_validation + .keys() + .iter() + .filter_map(|key| key.try_into().ok()) + .collect(); + + for pkey in &pkeys { + if dec_msg.verify(&pkey.primary_key).is_ok() { + let fp_r = hex::encode_upper(pkey.fingerprint()); + let len = fp_r.len() as libc::c_int; + let fp_c = CString::new(fp_r).unwrap(); + let fp = unsafe { libc::strdup(fp_c.as_ptr()) }; + + unsafe { + dc_hash_insert( + ret_signature_fingerprints, + fp as *const _, + len, + 1 as *mut _, + ) + }; + } + } + } + dec_msg.get_content() + }) + .ok() + .and_then(|content| content) + } else { + None + } } -/* symm. encryption */ -// TODO should return bool /rtn -pub unsafe fn dc_pgp_symm_encrypt( - context: &dc_context_t, +/// Symmetric encryption. +pub fn dc_pgp_symm_encrypt( passphrase: *const libc::c_char, plain: *const libc::c_void, plain_bytes: size_t, - ret_ctext_armored: *mut *mut libc::c_char, -) -> libc::c_int { - let mut success: libc::c_int = 0i32; - let mut decrypted: *mut rpgp::Message = 0 as *mut rpgp::Message; - if !(passphrase.is_null() - || plain == 0 as *mut libc::c_void - || plain_bytes == 0 - || ret_ctext_armored.is_null()) - { - decrypted = rpgp::rpgp_encrypt_bytes_with_password( - plain as *const uint8_t, - plain_bytes as usize, - passphrase, - ); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - *ret_ctext_armored = rpgp::rpgp_msg_to_armored_str(decrypted); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - success = 1i32 - } - } - } - if !decrypted.is_null() { - rpgp::rpgp_msg_drop(decrypted); - } +) -> Option { + assert!(!passphrase.is_null(), "invalid passphrase"); + assert!(!plain.is_null() && !plain_bytes > 0, "invalid input"); - success + let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() }; + let bytes = unsafe { std::slice::from_raw_parts(plain as *const u8, plain_bytes) }; + + let mut rng = thread_rng(); + let lit_msg = Message::new_literal_bytes("", bytes); + + let s2k = StringToKey::new_default(&mut rng); + let msg = lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || pw.into()); + + msg.and_then(|msg| msg.to_armored_string(None)).ok() } -// TODO should return bool /rtn -pub unsafe fn dc_pgp_symm_decrypt( - context: &dc_context_t, +/// Symmetric decryption. +pub fn dc_pgp_symm_decrypt( passphrase: *const libc::c_char, ctext: *const libc::c_void, ctext_bytes: size_t, - ret_plain_text: *mut *mut libc::c_void, - ret_plain_bytes: *mut size_t, -) -> libc::c_int { - let decrypted_bytes: *mut rpgp::cvec; - let mut success: libc::c_int = 0i32; - let encrypted: *mut rpgp::Message; - let mut decrypted: *mut rpgp::Message = 0 as *mut rpgp::Message; - encrypted = rpgp::rpgp_msg_from_bytes(ctext as *const uint8_t, ctext_bytes as usize); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - decrypted = rpgp::rpgp_msg_decrypt_with_password(encrypted, passphrase); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - decrypted_bytes = rpgp::rpgp_msg_to_bytes(decrypted); - if !(0 != dc_pgp_handle_rpgp_error(context)) { - *ret_plain_text = rpgp::rpgp_cvec_data(decrypted_bytes) as *mut libc::c_void; - *ret_plain_bytes = rpgp::rpgp_cvec_len(decrypted_bytes) as size_t; - free(decrypted_bytes as *mut libc::c_void); - success = 1i32 - } - } - } - if !encrypted.is_null() { - rpgp::rpgp_msg_drop(encrypted); - } - if !decrypted.is_null() { - rpgp::rpgp_msg_drop(decrypted); - } +) -> Option> { + assert!(!passphrase.is_null(), "invalid passphrase"); + assert!(!ctext.is_null() && !ctext_bytes > 0, "invalid input"); - success + let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() }; + let bytes = unsafe { std::slice::from_raw_parts(ctext as *const u8, ctext_bytes) }; + + let enc_msg = Message::from_bytes(Cursor::new(bytes)); + + enc_msg + .and_then(|msg| { + let mut decryptor = msg + .decrypt_with_password(|| pw.into()) + .expect("failed decryption"); + decryptor.next().expect("no message") + }) + .and_then(|msg| msg.get_content()) + .ok() + .and_then(|content| content) +} + +/// Calculate the SHA256 hash of the given bytes. +pub fn dc_hash_sha256(bytes_ptr: *const u8, bytes_len: libc::size_t) -> (*mut u8, libc::size_t) { + assert!(!bytes_ptr.is_null()); + assert!(bytes_len > 0); + + let bytes = unsafe { std::slice::from_raw_parts(bytes_ptr, bytes_len) }; + let result = Sha256::digest(bytes); + + let mut r = result.to_vec(); + r.shrink_to_fit(); + + let ptr = r.as_ptr(); + let len = r.len(); + std::mem::forget(r); + + (ptr as *mut _, len) } diff --git a/src/dc_qr.rs b/src/dc_qr.rs index ee447c006..e9611e560 100644 --- a/src/dc_qr.rs +++ b/src/dc_qr.rs @@ -31,7 +31,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m let mut name: *mut libc::c_char = 0 as *mut libc::c_char; let mut invitenumber: *mut libc::c_char = 0 as *mut libc::c_char; let mut auth: *mut libc::c_char = 0 as *mut libc::c_char; - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); let mut qr_parsed: *mut dc_lot_t = dc_lot_new(); let mut chat_id: uint32_t = 0i32 as uint32_t; let mut device_msg: *mut libc::c_char = 0 as *mut libc::c_char; @@ -85,7 +85,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m } dc_param_unref(param); } - fingerprint = dc_normalize_fingerprint(payload); + fingerprint = dc_normalize_fingerprint_c(payload); current_block = 5023038348526654800; } else if strncasecmp( qr, @@ -240,7 +240,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m if !fingerprint.is_null() { if addr.is_null() || invitenumber.is_null() || auth.is_null() { if 0 != dc_apeerstate_load_by_fingerprint( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), fingerprint, ) { @@ -248,7 +248,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m (*qr_parsed).id = dc_add_or_lookup_contact( context, 0 as *const libc::c_char, - (*peerstate).addr, + peerstate.addr, 0x80i32, 0 as *mut libc::c_int, ); @@ -262,10 +262,11 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m device_msg = dc_mprintf( b"%s verified.\x00" as *const u8 as *const libc::c_char, - (*peerstate).addr, + peerstate.addr, ) } else { - (*qr_parsed).text1 = dc_format_fingerprint(fingerprint); + (*qr_parsed).text1 = + dc_format_fingerprint_c(fingerprint); (*qr_parsed).state = 230i32 } } else { @@ -323,7 +324,7 @@ pub unsafe fn dc_check_qr(context: &dc_context_t, qr: *const libc::c_char) -> *m } free(addr as *mut libc::c_void); free(fingerprint as *mut libc::c_void); - dc_apeerstate_unref(peerstate); + dc_apeerstate_unref(&mut peerstate); free(payload as *mut libc::c_void); free(name as *mut libc::c_void); free(invitenumber as *mut libc::c_void); diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 3c7f44fe7..92eb9f74b 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -20,13 +20,13 @@ use crate::dc_mimeparser::*; use crate::dc_move::*; use crate::dc_msg::*; use crate::dc_param::*; +use crate::dc_pgp::dc_hash_sha256; use crate::dc_securejoin::*; use crate::dc_sqlite3::*; use crate::dc_stock::*; use crate::dc_strbuilder::*; use crate::dc_strencode::*; use crate::dc_tools::*; -use crate::pgp; use crate::types::*; use crate::x::*; @@ -1756,7 +1756,7 @@ unsafe fn create_adhoc_grp_id( i += 1 } /* make sha-256 from the string */ - let binary_hash: *mut crate::pgp::cvec = pgp::rpgp_hash_sha256( + let (binary_hash, binary_hash_len) = dc_hash_sha256( member_cs.buf as *const uint8_t, strlen(member_cs.buf) as usize, ); @@ -1768,11 +1768,11 @@ unsafe fn create_adhoc_grp_id( sprintf( &mut *ret.offset((i * 2i32) as isize) as *mut libc::c_char, b"%02x\x00" as *const u8 as *const libc::c_char, - *pgp::rpgp_cvec_data(binary_hash).offset(i as isize) as libc::c_int, + *binary_hash.offset(i as isize) as libc::c_int, ); i += 1 } - pgp::rpgp_cvec_drop(binary_hash); + let _v = Vec::from_raw_parts(binary_hash, binary_hash_len, binary_hash_len); } } dc_array_free_ptr(member_addrs); @@ -1861,7 +1861,7 @@ unsafe fn check_verified_properties( let mut current_block: u64; let mut everythings_okay: libc::c_int = 0i32; let contact: *mut dc_contact_t = dc_contact_new(context); - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); let mut to_ids_str: *mut libc::c_char = 0 as *mut libc::c_char; let mut q3: *mut libc::c_char = 0 as *mut libc::c_char; let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt; @@ -1884,10 +1884,10 @@ unsafe fn check_verified_properties( // and results in group-splits otherwise. if from_id != 1i32 as libc::c_uint { if 0 == dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), (*contact).addr, - ) || dc_contact_is_verified_ex(contact, peerstate) != 2i32 + ) || dc_contact_is_verified_ex(contact, Some(&peerstate)) != 2i32 { *failure_reason = dc_mprintf( b"%s. See \"Info\" for details.\x00" as *const u8 as *const libc::c_char, @@ -1898,7 +1898,7 @@ unsafe fn check_verified_properties( current_block = 14837890932895028253; } else if 0 == dc_apeerstate_has_verified_key( - peerstate, + &&peerstate, (*(*mimeparser).e2ee_helper).signatures, ) { @@ -1940,19 +1940,19 @@ unsafe fn check_verified_properties( ) .is_null() && 0 != dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), to_addr, ) { if 0 == is_verified || strcmp( - (*peerstate).verified_key_fingerprint, - (*peerstate).public_key_fingerprint, + peerstate.verified_key_fingerprint, + peerstate.public_key_fingerprint, ) != 0i32 && strcmp( - (*peerstate).verified_key_fingerprint, - (*peerstate).gossip_key_fingerprint, + peerstate.verified_key_fingerprint, + peerstate.gossip_key_fingerprint, ) != 0i32 { dc_log_info( @@ -1962,14 +1962,10 @@ unsafe fn check_verified_properties( (*contact).addr, to_addr, ); - dc_apeerstate_set_verified( - peerstate, - 0i32, - (*peerstate).gossip_key_fingerprint, - 2i32, - ); + let fp = peerstate.gossip_key_fingerprint; + dc_apeerstate_set_verified(&mut peerstate, 0i32, fp, 2i32); dc_apeerstate_save_to_db( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), 0i32, ); @@ -2002,7 +1998,7 @@ unsafe fn check_verified_properties( } sqlite3_finalize(stmt); dc_contact_unref(contact); - dc_apeerstate_unref(peerstate); + dc_apeerstate_unref(&mut peerstate); free(to_ids_str as *mut libc::c_void); sqlite3_free(q3 as *mut libc::c_void); return everythings_okay; diff --git a/src/dc_securejoin.rs b/src/dc_securejoin.rs index 3d60cc2c3..deace608b 100644 --- a/src/dc_securejoin.rs +++ b/src/dc_securejoin.rs @@ -148,30 +148,23 @@ pub unsafe fn dc_get_securejoin_qr( } unsafe fn get_self_fingerprint(context: &dc_context_t) -> *mut libc::c_char { - let self_addr: *mut libc::c_char; - let self_key: *mut dc_key_t = dc_key_new(); - let mut fingerprint: *mut libc::c_char = 0 as *mut libc::c_char; - self_addr = dc_sqlite3_get_config( + let self_addr = dc_sqlite3_get_config( context, &context.sql.clone().read().unwrap(), b"configured_addr\x00" as *const u8 as *const libc::c_char, 0 as *const libc::c_char, ); - if !(self_addr.is_null() - || 0 == dc_key_load_self_public( - context, - self_key, - self_addr, - &context.sql.clone().read().unwrap(), - )) - { - fingerprint = dc_key_get_fingerprint(context, self_key); - fingerprint.is_null(); + if self_addr.is_null() { + return std::ptr::null_mut(); } - free(self_addr as *mut libc::c_void); - dc_key_unref(self_key); - fingerprint + if let Some(key) = + Key::from_self_public(context, self_addr, &context.sql.clone().read().unwrap()) + { + return key.fingerprint_c(); + } + + std::ptr::null_mut() } pub unsafe fn dc_join_securejoin(context: &dc_context_t, qr: *const libc::c_char) -> uint32_t { @@ -360,7 +353,7 @@ unsafe fn fingerprint_equals_sender( let mut fingerprint_equal: libc::c_int = 0i32; let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id); let contact: *mut dc_contact_t = dc_contact_new(context); - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); let mut fingerprint_normalized: *mut libc::c_char = 0 as *mut libc::c_char; if !(dc_array_get_cnt(contacts) != 1) { if !(!dc_contact_load_from_db( @@ -369,13 +362,13 @@ unsafe fn fingerprint_equals_sender( dc_array_get_id(contacts, 0i32 as size_t), ) || 0 == dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), (*contact).addr, )) { - fingerprint_normalized = dc_normalize_fingerprint(fingerprint); - if strcasecmp(fingerprint_normalized, (*peerstate).public_key_fingerprint) == 0i32 { + fingerprint_normalized = dc_normalize_fingerprint_c(fingerprint); + if strcasecmp(fingerprint_normalized, peerstate.public_key_fingerprint) == 0i32 { fingerprint_equal = 1i32 } } @@ -984,19 +977,19 @@ unsafe fn mark_peer_as_verified( let mut peerstate = dc_apeerstate_new(context); if !(0 == dc_apeerstate_load_by_fingerprint( - peerstate, + &mut peerstate, &context.sql.clone().read().unwrap(), fingerprint, )) { - if !(0 == dc_apeerstate_set_verified(peerstate, 1i32, fingerprint, 2i32)) { - (*peerstate).prefer_encrypt = 1i32; - (*peerstate).to_save |= 0x2i32; - dc_apeerstate_save_to_db(peerstate, &context.sql.clone().read().unwrap(), 0i32); + if !(0 == dc_apeerstate_set_verified(&mut peerstate, 1i32, fingerprint, 2i32)) { + peerstate.prefer_encrypt = 1i32; + peerstate.to_save |= 0x2i32; + dc_apeerstate_save_to_db(&mut peerstate, &context.sql.clone().read().unwrap(), 0i32); success = 1i32 } } - dc_apeerstate_unref(peerstate); + dc_apeerstate_unref(&mut peerstate); success } @@ -1054,45 +1047,43 @@ unsafe fn encrypted_and_signed( 1 } -pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: *mut dc_apeerstate_t) { +pub unsafe fn dc_handle_degrade_event(context: &dc_context_t, peerstate: &dc_apeerstate_t) { let stmt; let contact_id: uint32_t; let mut contact_chat_id: uint32_t = 0i32 as uint32_t; - if !peerstate.is_null() { - // - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal - // - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes - // together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother - // with things they cannot fix, so the user is just kicked from the verified group - // (and he will know this and can fix this) - if 0 != (*peerstate).degrade_event & 0x2i32 { - stmt = dc_sqlite3_prepare( + + // - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal + // - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes + // together with DC_DE_FINGERPRINT_CHANGED which is logged, the idea is not to bother + // with things they cannot fix, so the user is just kicked from the verified group + // (and he will know this and can fix this) + if 0 != peerstate.degrade_event & 0x2i32 { + stmt = dc_sqlite3_prepare( + context, + &context.sql.clone().read().unwrap(), + b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char, + ); + sqlite3_bind_text(stmt, 1i32, peerstate.addr, -1i32, None); + sqlite3_step(stmt); + contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t; + sqlite3_finalize(stmt); + if !(contact_id == 0i32 as libc::c_uint) { + dc_create_or_lookup_nchat_by_contact_id( context, - &context.sql.clone().read().unwrap(), - b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char, + contact_id, + 2i32, + &mut contact_chat_id, + 0 as *mut libc::c_int, + ); + let msg: *mut libc::c_char = dc_stock_str_repl_string(context, 37i32, peerstate.addr); + dc_add_device_msg(context, contact_chat_id, msg); + free(msg as *mut libc::c_void); + (context.cb)( + context, + Event::CHAT_MODIFIED, + contact_chat_id as uintptr_t, + 0i32 as uintptr_t, ); - sqlite3_bind_text(stmt, 1i32, (*peerstate).addr, -1i32, None); - sqlite3_step(stmt); - contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t; - sqlite3_finalize(stmt); - if !(contact_id == 0i32 as libc::c_uint) { - dc_create_or_lookup_nchat_by_contact_id( - context, - contact_id, - 2i32, - &mut contact_chat_id, - 0 as *mut libc::c_int, - ); - let msg: *mut libc::c_char = - dc_stock_str_repl_string(context, 37i32, (*peerstate).addr); - dc_add_device_msg(context, contact_chat_id, msg); - free(msg as *mut libc::c_void); - (context.cb)( - context, - Event::CHAT_MODIFIED, - contact_chat_id as uintptr_t, - 0i32 as uintptr_t, - ); - } } - }; + } } diff --git a/src/dc_sqlite3.rs b/src/dc_sqlite3.rs index 054bc85a4..b8bef6864 100644 --- a/src/dc_sqlite3.rs +++ b/src/dc_sqlite3.rs @@ -914,16 +914,16 @@ pub unsafe fn dc_sqlite3_open( as *const libc::c_char, ); while sqlite3_step(stmt) == 100 { - let peerstate: *mut dc_apeerstate_t = dc_apeerstate_new(context); + let mut peerstate = dc_apeerstate_new(context); if 0 != dc_apeerstate_load_by_addr( - peerstate, + &mut peerstate, sql, sqlite3_column_text(stmt, 0) as *const libc::c_char, - ) && 0 != dc_apeerstate_recalc_fingerprint(peerstate) + ) && 0 != dc_apeerstate_recalc_fingerprint(&mut peerstate) { - dc_apeerstate_save_to_db(peerstate, sql, 0); + dc_apeerstate_save_to_db(&mut peerstate, sql, 0); } - dc_apeerstate_unref(peerstate); + dc_apeerstate_unref(&mut peerstate); } sqlite3_finalize(stmt); } diff --git a/src/lib.rs b/src/lib.rs index 92966e158..b5386f084 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,16 +14,14 @@ ptr_wrapping_offset_from )] -#[macro_use] -extern crate failure; #[macro_use] extern crate num_derive; +#[macro_use] +extern crate smallvec; #[macro_use] pub mod dc_log; -mod pgp; - pub mod dc_aheader; pub mod dc_apeerstate; diff --git a/src/pgp/c_vec.rs b/src/pgp/c_vec.rs deleted file mode 100644 index 651095aa4..000000000 --- a/src/pgp/c_vec.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::slice; - -/// Represents a vector, that can be passed to C land. -/// Has to be deallocated using [rpgp_cvec_drop], otherwise leaks memory. -#[repr(C)] -#[derive(Debug)] -pub struct cvec { - data: *mut u8, - len: libc::size_t, -} - -impl PartialEq for cvec { - fn eq(&self, other: &cvec) -> bool { - if self.len != other.len { - return false; - } - - unsafe { - slice::from_raw_parts(self.data, self.len) - == slice::from_raw_parts(other.data, other.len) - } - } -} - -impl Eq for cvec {} - -impl Into for Vec { - fn into(mut self) -> cvec { - self.shrink_to_fit(); - assert!(self.len() == self.capacity()); - - let res = cvec { - data: self.as_mut_ptr(), - len: self.len() as libc::size_t, - }; - - // prevent deallocation in Rust - std::mem::forget(self); - res - } -} - -impl Into> for cvec { - fn into(self) -> Vec { - unsafe { Vec::from_raw_parts(self.data, self.len, self.len) } - } -} - -/// Get the length of the data of the given [cvec]. -pub unsafe fn rpgp_cvec_len(cvec_ptr: *mut cvec) -> libc::size_t { - assert!(!cvec_ptr.is_null()); - - let cvec = &*cvec_ptr; - cvec.len -} - -/// Get a pointer to the data of the given [cvec]. -pub unsafe fn rpgp_cvec_data(cvec_ptr: *mut cvec) -> *const u8 { - assert!(!cvec_ptr.is_null()); - - let cvec = &*cvec_ptr; - cvec.data -} - -/// Free the given [cvec]. -pub unsafe fn rpgp_cvec_drop(cvec_ptr: *mut cvec) { - assert!(!cvec_ptr.is_null()); - - let v = &*cvec_ptr; - let _ = Vec::from_raw_parts(v.data, v.len, v.len); - // Drop -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_cvec() { - for i in 0..100 { - let a = vec![i as u8; i * 10]; - let b: cvec = a.clone().into(); - let c: Vec = b.into(); - assert_eq!(a, c); - } - } -} diff --git a/src/pgp/errors.rs b/src/pgp/errors.rs deleted file mode 100644 index 3b25fefcf..000000000 --- a/src/pgp/errors.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::cell::RefCell; -use std::ffi::CString; -use std::ptr; - -use failure::Error; -use libc::{c_char, c_int}; - -thread_local! { - static LAST_ERROR: RefCell>> = RefCell::new(None); -} - -/// Update the most recent error, clearing whatever may have been there before. -pub fn update_last_error(err: Error) { - { - // Print a pseudo-backtrace for this error, following back each error's - // cause until we reach the root error. - let mut cause = err.as_fail().cause(); - while let Some(parent_err) = cause { - cause = parent_err.cause(); - } - } - - LAST_ERROR.with(|prev| { - *prev.borrow_mut() = Some(Box::new(err)); - }); -} - -/// Retrieve the most recent error, clearing it in the process. -pub fn take_last_error() -> Option> { - LAST_ERROR.with(|prev| prev.borrow_mut().take()) -} - -/// Calculate the number of bytes in the last error's error message **not** -/// including any trailing `null` characters. -pub extern "C" fn rpgp_last_error_length() -> c_int { - LAST_ERROR.with(|prev| match *prev.borrow() { - Some(ref err) => err.to_string().len() as c_int + 1, - None => 0, - }) -} - -/// Write the most recent error message into a caller-provided buffer as a UTF-8 -/// string, returning the number of bytes written. -/// -/// # Note -/// -/// This writes a **UTF-8** string into the buffer. Windows users may need to -/// convert it to a UTF-16 "unicode" afterwards. -/// -/// If there are no recent errors then this returns `0` (because we wrote 0 -/// bytes). `-1` is returned if there are any errors, for example when passed a -/// null pointer or a buffer of insufficient size. -pub unsafe fn rpgp_last_error_message() -> *mut c_char { - let last_error = match take_last_error() { - Some(err) => err, - None => return ptr::null_mut(), - }; - - let error_message = last_error.to_string(); - - CString::new(error_message) - .expect("CString alloc failed") - .into_raw() -} diff --git a/src/pgp/hash.rs b/src/pgp/hash.rs deleted file mode 100644 index c98f8966e..000000000 --- a/src/pgp/hash.rs +++ /dev/null @@ -1,15 +0,0 @@ -use sha2::{Digest, Sha256}; -use std::slice; - -use crate::pgp::cvec; - -/// Calculate the SHA256 hash of the given bytes. -pub unsafe fn rpgp_hash_sha256(bytes_ptr: *const u8, bytes_len: libc::size_t) -> *mut cvec { - assert!(!bytes_ptr.is_null()); - assert!(bytes_len > 0); - - let bytes = slice::from_raw_parts(bytes_ptr, bytes_len); - let result = Sha256::digest(bytes); - - Box::into_raw(Box::new(result.to_vec().into())) -} diff --git a/src/pgp/key.rs b/src/pgp/key.rs deleted file mode 100644 index c15278bdd..000000000 --- a/src/pgp/key.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::ffi::CString; -use std::io::Cursor; -use std::slice; - -use libc::c_char; -use pgp::composed::{from_armor_many, from_bytes_many, PublicOrSecret}; -use pgp::types::KeyTrait; - -use crate::pgp::cvec; - -pub type public_or_secret_key = PublicOrSecret; - -/// Creates an in-memory representation of a PGP key, based on the armor file given. -/// The returned pointer should be stored, and reused when calling methods "on" this key. -/// When done with it [rpgp_key_drop] should be called, to free the memory. -#[allow(dead_code)] -pub unsafe fn rpgp_key_from_armor(raw: *const u8, len: libc::size_t) -> *mut public_or_secret_key { - assert!(!raw.is_null()); - assert!(len > 0); - - let bytes = slice::from_raw_parts(raw, len); - let (mut keys, _headers) = try_ffi!(from_armor_many(Cursor::new(bytes)), "failed to parse"); - - let key = try_ffi!( - try_ffi!( - keys.nth(0).ok_or_else(|| format_err!("no valid key found")), - "failed to parse key" - ), - "failed to parse key" - ); - - try_ffi!(key.verify(), "failed to verify key"); - - Box::into_raw(Box::new(key)) -} - -/// Creates an in-memory representation of a PGP key, based on the serialized bytes given. -pub unsafe extern "C" fn rpgp_key_from_bytes( - raw: *const u8, - len: libc::size_t, -) -> *mut public_or_secret_key { - assert!(!raw.is_null()); - assert!(len > 0); - - let bytes = slice::from_raw_parts(raw, len); - let mut keys = from_bytes_many(Cursor::new(bytes)); - - let key = try_ffi!( - try_ffi!( - keys.nth(0).ok_or_else(|| format_err!("no valid key found")), - "failed to parse key" - ), - "failed to parse key" - ); - - try_ffi!(key.verify(), "failed to verify key"); - - Box::into_raw(Box::new(key)) -} - -/// Returns the KeyID for the passed in key. The caller is responsible to call [rpgp_string_drop] with the returned memory, to free it. -#[allow(dead_code)] -pub unsafe fn rpgp_key_id(key_ptr: *mut public_or_secret_key) -> *mut c_char { - assert!(!key_ptr.is_null()); - - let key = &*key_ptr; - let id = try_ffi!( - CString::new(hex::encode(&key.key_id())), - "failed to allocate string" - ); - - id.into_raw() -} - -/// Returns the Fingerprint for the passed in key. The caller is responsible to call [rpgp_cvec_drop] with the returned memory, to free it. -pub unsafe fn rpgp_key_fingerprint(key_ptr: *mut public_or_secret_key) -> *mut cvec { - assert!(!key_ptr.is_null()); - - let key = &*key_ptr; - let fingerprint = key.fingerprint(); - - Box::into_raw(Box::new(fingerprint.into())) -} - -/// Returns `true` if this key is a public key, false otherwise. -pub unsafe fn rpgp_key_is_public(key_ptr: *mut public_or_secret_key) -> bool { - assert!(!key_ptr.is_null()); - - (&*key_ptr).is_public() -} - -/// Returns `true` if this key is a secret key, false otherwise. -pub unsafe fn rpgp_key_is_secret(key_ptr: *mut public_or_secret_key) -> bool { - assert!(!key_ptr.is_null()); - - (&*key_ptr).is_secret() -} - -/// Frees the memory of the passed in key, making the pointer invalid after this method was called. -pub unsafe fn rpgp_key_drop(key_ptr: *mut public_or_secret_key) { - assert!(!key_ptr.is_null()); - - let _key = &*key_ptr; - // Drop -} - -#[cfg(test)] -mod tests { - use super::*; - use std::ffi::CStr; - - use crate::pgp::{ - rpgp_create_x25519_skey, rpgp_cvec_data, rpgp_cvec_drop, rpgp_cvec_len, rpgp_skey_to_bytes, - }; - - #[test] - fn test_fingerprint() { - let user_id = CStr::from_bytes_with_nul(b"\0").unwrap(); - - unsafe { - // Create the actual key - let skey = rpgp_create_x25519_skey(user_id.as_ptr()); - - // Serialize secret key into bytes - let skey_bytes = rpgp_skey_to_bytes(skey); - - let key = rpgp_key_from_bytes(rpgp_cvec_data(skey_bytes), rpgp_cvec_len(skey_bytes)); - assert!(rpgp_key_is_secret(key)); - - let fingerprint1 = rpgp_key_fingerprint(key); - - // get fingerprint directly - let mut fingerprint2: cvec = (&*skey).fingerprint().into(); - - assert_eq!(*fingerprint1, fingerprint2); - - // cleanup - rpgp_cvec_drop(skey_bytes); - rpgp_cvec_drop(fingerprint1); - rpgp_cvec_drop(&mut fingerprint2); - } - } -} diff --git a/src/pgp/macros.rs b/src/pgp/macros.rs deleted file mode 100644 index 61768194b..000000000 --- a/src/pgp/macros.rs +++ /dev/null @@ -1,12 +0,0 @@ -#[macro_export] -macro_rules! try_ffi { - ($e:expr, $fmt:expr) => { - match $e { - Ok(v) => v, - Err(err) => { - $crate::pgp::errors::update_last_error(err.into()); - return std::ptr::null_mut(); - } - } - }; -} diff --git a/src/pgp/message.rs b/src/pgp/message.rs deleted file mode 100644 index 82cb733f5..000000000 --- a/src/pgp/message.rs +++ /dev/null @@ -1,349 +0,0 @@ -use std::ffi::{CStr, CString}; -use std::io::Cursor; -use std::slice; - -use libc::c_char; -use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey}; -use pgp::types::{CompressionAlgorithm, KeyTrait, StringToKey}; -use rand::thread_rng; - -use crate::pgp::{cvec, signed_public_key, signed_secret_key, update_last_error}; -pub use pgp::composed::Message; -pub type message = Message; - -/// Parse an armored message. -pub unsafe fn rpgp_msg_from_armor(msg_ptr: *const u8, msg_len: libc::size_t) -> *mut message { - assert!(!msg_ptr.is_null()); - assert!(msg_len > 0); - - let enc_msg = slice::from_raw_parts(msg_ptr, msg_len); - - let (msg, _headers) = try_ffi!( - Message::from_armor_single(Cursor::new(enc_msg)), - "invalid message" - ); - - Box::into_raw(Box::new(msg)) -} - -/// Parse a message in bytes format. -pub unsafe extern "C" fn rpgp_msg_from_bytes( - msg_ptr: *const u8, - msg_len: libc::size_t, -) -> *mut message { - assert!(!msg_ptr.is_null()); - assert!(msg_len > 0); - - let enc_msg = slice::from_raw_parts(msg_ptr, msg_len); - - let msg = try_ffi!(Message::from_bytes(Cursor::new(enc_msg)), "invalid message"); - - Box::into_raw(Box::new(msg)) -} - -/// Decrypt the passed in message, using a password. -pub unsafe fn rpgp_msg_decrypt_with_password( - msg_ptr: *const message, - password_ptr: *const c_char, -) -> *mut message { - assert!(!msg_ptr.is_null()); - assert!(!password_ptr.is_null()); - - let msg = &*msg_ptr; - let password = CStr::from_ptr(password_ptr); - let password_str = try_ffi!(password.to_str(), "invalid password"); - let mut decryptor = try_ffi!( - msg.decrypt_with_password(|| password_str.into()), - "failed to decrypt message" - ); - let decrypted_msg = try_ffi!( - try_ffi!( - decryptor.next().ok_or_else(|| format_err!("")), - "no message found" - ), - "failed to decrypt message" - ); - - Box::into_raw(Box::new(decrypted_msg)) -} - -/// Decrypt the passed in message, without attempting to use a password. -pub unsafe fn rpgp_msg_decrypt_no_pw( - msg_ptr: *const message, - skeys_ptr: *const *const signed_secret_key, - skeys_len: libc::size_t, - pkeys_ptr: *const *const signed_public_key, - pkeys_len: libc::size_t, -) -> *mut message_decrypt_result { - assert!(!msg_ptr.is_null()); - assert!(!skeys_ptr.is_null()); - assert!(skeys_len > 0); - - let msg = &*msg_ptr; - let skeys_raw = slice::from_raw_parts(skeys_ptr, skeys_len); - let skeys = skeys_raw - .iter() - .map(|k| { - let v: &SignedSecretKey = &**k; - v - }) - .collect::>(); - - let pkeys = if pkeys_ptr.is_null() || pkeys_len == 0 { - None - } else { - Some(slice::from_raw_parts(pkeys_ptr, pkeys_len)) - }; - - let (mut decryptor, _) = try_ffi!( - msg.decrypt(|| "".into(), || "".into(), &skeys[..]), - "failed to decrypt message" - ); - - // TODO: how to handle the case when we detect multiple messages? - let dec_msg = try_ffi!( - try_ffi!( - decryptor.next().ok_or_else(|| format_err!("no message")), - "no message found" - ), - "failed to decrypt message" - ); - - let (valid_ids_ptr, valid_ids_len) = if let Some(pkeys) = pkeys { - let mut valid_ids = pkeys - .iter() - .filter_map(|pkey| match dec_msg.verify(&(**pkey).primary_key) { - Ok(_) => Some( - CString::new(hex::encode_upper(&(&**pkey).fingerprint())) - .expect("failed to allocate") - .into_raw(), - ), - Err(_) => None, - }) - .collect::>(); - - valid_ids.shrink_to_fit(); - let res = (valid_ids.as_mut_ptr(), valid_ids.len()); - std::mem::forget(valid_ids); - res - } else { - (std::ptr::null_mut(), 0) - }; - - Box::into_raw(Box::new(message_decrypt_result { - message_ptr: Box::into_raw(Box::new(dec_msg)), - valid_ids_ptr, - valid_ids_len, - })) -} - -/// Message decryption result. -#[repr(C)] -pub struct message_decrypt_result { - /// A pointer to the decrypted message. - pub message_ptr: *mut message, - /// Pointer to a list of fingerprints which verified the signature. - pub valid_ids_ptr: *mut *mut c_char, - pub valid_ids_len: libc::size_t, -} - -/// Free a [message_decrypt_result]. -pub unsafe fn rpgp_message_decrypt_result_drop(res_ptr: *mut message_decrypt_result) { - assert!(!res_ptr.is_null()); - - let res = &*res_ptr; - let _msg = &*res.message_ptr; - let _ids = Vec::from_raw_parts(res.valid_ids_ptr, res.valid_ids_len, res.valid_ids_len); - // Drop -} - -/// Returns the underlying data of the given message. -/// Fails when the message is encrypted. Decompresses compressed messages. -pub unsafe fn rpgp_msg_to_bytes(msg_ptr: *const message) -> *mut cvec { - assert!(!msg_ptr.is_null()); - - let msg = &*msg_ptr; - - let result = try_ffi!(msg.get_content(), "failed to extract content"); - match result { - Some(data) => Box::into_raw(Box::new(data.into())), - None => { - update_last_error(format_err!("called on encrypted message").into()); - std::ptr::null_mut() - } - } -} - -/// Encodes the message into its ascii armored representation. -pub unsafe fn rpgp_msg_to_armored(msg_ptr: *const message) -> *mut cvec { - assert!(!msg_ptr.is_null()); - - let msg = &*msg_ptr; - - let result = try_ffi!( - msg.to_armored_bytes(None), - "failed to encode message to ASCII Armor" - ); - - Box::into_raw(Box::new(result.into())) -} - -/// Encodes the message into its ascii armored representation, returning a string. -pub unsafe fn rpgp_msg_to_armored_str(msg_ptr: *const message) -> *mut c_char { - assert!(!msg_ptr.is_null()); - - let msg = &*msg_ptr; - - let result = try_ffi!( - msg.to_armored_string(None), - "failed to encode message to ASCII Armor" - ); - - CString::new(result).expect("allocation failed").into_raw() -} - -/// Free a [message], that was created by rpgp. -pub unsafe fn rpgp_msg_drop(msg_ptr: *mut message) { - assert!(!msg_ptr.is_null()); - - let _ = &*msg_ptr; - // Drop -} - -/// Get the number of fingerprints of a given encrypted message. -#[allow(dead_code)] -pub unsafe fn rpgp_msg_recipients_len(msg_ptr: *mut message) -> u32 { - assert!(!msg_ptr.is_null()); - - let msg = &*msg_ptr; - - let list = msg.get_recipients(); - - list.len() as u32 -} - -/// Get the fingerprint of a given encrypted message, by index, in hexformat. -#[allow(dead_code)] -pub unsafe fn rpgp_msg_recipients_get(msg_ptr: *mut message, i: u32) -> *mut c_char { - assert!(!msg_ptr.is_null()); - - let msg = &*msg_ptr; - - let list = msg.get_recipients(); - if (i as usize) < list.len() { - CString::new(hex::encode(&list[i as usize])) - .expect("allocation failure") - .into_raw() - } else { - std::ptr::null_mut() - } -} - -pub unsafe fn rpgp_encrypt_bytes_to_keys( - bytes_ptr: *const u8, - bytes_len: libc::size_t, - pkeys_ptr: *const *const signed_public_key, - pkeys_len: libc::size_t, -) -> *mut message { - assert!(!bytes_ptr.is_null()); - assert!(bytes_len > 0); - assert!(!pkeys_ptr.is_null()); - assert!(pkeys_len > 0); - - let pkeys_raw = slice::from_raw_parts(pkeys_ptr, pkeys_len); - let pkeys = pkeys_raw - .iter() - .map(|k| { - let v: &SignedPublicKey = &**k; - v - }) - .collect::>(); - - let bytes = slice::from_raw_parts(bytes_ptr, bytes_len); - - let mut rng = thread_rng(); - let lit_msg = Message::new_literal_bytes("", bytes); - - let msg = try_ffi!( - lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys), - "failed to encrypt" - ); - - Box::into_raw(Box::new(msg)) -} - -pub unsafe fn rpgp_sign_encrypt_bytes_to_keys( - bytes_ptr: *const u8, - bytes_len: libc::size_t, - pkeys_ptr: *const *const signed_public_key, - pkeys_len: libc::size_t, - skey_ptr: *const signed_secret_key, -) -> *mut message { - assert!(!bytes_ptr.is_null()); - assert!(bytes_len > 0); - assert!(!pkeys_ptr.is_null()); - assert!(pkeys_len > 0); - assert!(!skey_ptr.is_null()); - - let pkeys_raw = slice::from_raw_parts(pkeys_ptr, pkeys_len); - let pkeys = pkeys_raw - .iter() - .map(|k| { - let v: &SignedPublicKey = &**k; - v - }) - .collect::>(); - - let skey = &*skey_ptr; - - let bytes = slice::from_raw_parts(bytes_ptr, bytes_len); - - let mut rng = thread_rng(); - - let lit_msg = Message::new_literal_bytes("", bytes); - let signed_msg = try_ffi!( - lit_msg.sign(&skey, || "".into(), Default::default()), - "failed to sign" - ); - - let compressed_msg = try_ffi!( - signed_msg.compress(CompressionAlgorithm::ZLIB), - "failed to compress" - ); - - let encrypted_msg = try_ffi!( - compressed_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys), - "failed to encrypt" - ); - - Box::into_raw(Box::new(encrypted_msg)) -} - -pub unsafe fn rpgp_encrypt_bytes_with_password( - bytes_ptr: *const u8, - bytes_len: libc::size_t, - password_ptr: *const c_char, -) -> *mut message { - assert!(!bytes_ptr.is_null()); - assert!(!password_ptr.is_null()); - assert!(bytes_len > 0); - - let bytes = slice::from_raw_parts(bytes_ptr, bytes_len); - - let mut rng = thread_rng(); - let lit_msg = Message::new_literal_bytes("", bytes); - - let password = CStr::from_ptr(password_ptr); - let password_str = try_ffi!(password.to_str(), "invalid password"); - - let s2k = StringToKey::new_default(&mut rng); - - let msg = try_ffi!( - lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || { - password_str.into() - }), - "failed to encrypt" - ); - - Box::into_raw(Box::new(msg)) -} diff --git a/src/pgp/mod.rs b/src/pgp/mod.rs deleted file mode 100644 index f0afcc19c..000000000 --- a/src/pgp/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[macro_use] -mod macros; - -mod c_vec; -mod errors; -mod hash; -mod key; -mod message; -mod public_key; -mod secret_key; - -pub use self::c_vec::*; -pub use self::errors::*; -pub use self::hash::*; -pub use self::key::*; -pub use self::message::*; -pub use self::public_key::*; -pub use self::secret_key::*; - -/// Free string, that was created by rpgp. -pub unsafe fn rpgp_string_drop(p: *mut libc::c_char) { - let _ = std::ffi::CString::from_raw(p); - // Drop -} diff --git a/src/pgp/public_key.rs b/src/pgp/public_key.rs deleted file mode 100644 index 80f6bbecc..000000000 --- a/src/pgp/public_key.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::ffi::CString; -use std::io::Cursor; -use std::slice; - -use libc::c_char; -use pgp::composed::{Deserializable, SignedPublicKey}; -use pgp::ser::Serialize; -use pgp::types::KeyTrait; - -use crate::pgp::cvec; - -pub type signed_public_key = SignedPublicKey; - -/// Parse a serialized public key, into the native rPGP memory representation. -pub unsafe fn rpgp_pkey_from_bytes(raw: *const u8, len: libc::size_t) -> *mut signed_public_key { - assert!(!raw.is_null()); - assert!(len > 0); - - let bytes = slice::from_raw_parts(raw, len); - let key = try_ffi!( - SignedPublicKey::from_bytes(Cursor::new(bytes)), - "invalid public key" - ); - - try_ffi!(key.verify(), "failed to verify key"); - - Box::into_raw(Box::new(key)) -} - -/// Serialize the [signed_public_key] to bytes. -pub unsafe extern "C" fn rpgp_pkey_to_bytes(pkey_ptr: *mut signed_public_key) -> *mut cvec { - assert!(!pkey_ptr.is_null()); - - let pkey = &*pkey_ptr; - - let mut res = Vec::new(); - try_ffi!(pkey.to_writer(&mut res), "failed to serialize key"); - - Box::into_raw(Box::new(res.into())) -} - -/// Get the key id of the given [signed_public_key]. -#[allow(dead_code)] -pub unsafe fn rpgp_pkey_key_id(pkey_ptr: *mut signed_public_key) -> *mut c_char { - assert!(!pkey_ptr.is_null()); - - let pkey = &*pkey_ptr; - let id = try_ffi!( - CString::new(hex::encode(&pkey.key_id())), - "failed to allocate string" - ); - - id.into_raw() -} - -/// Free the given [signed_public_key]. -pub unsafe fn rpgp_pkey_drop(pkey_ptr: *mut signed_public_key) { - assert!(!pkey_ptr.is_null()); - - let _pkey = &*pkey_ptr; - // Drop -} diff --git a/src/pgp/secret_key.rs b/src/pgp/secret_key.rs deleted file mode 100644 index b727a086b..000000000 --- a/src/pgp/secret_key.rs +++ /dev/null @@ -1,194 +0,0 @@ -use std::ffi::{CStr, CString}; -use std::io::Cursor; -use std::slice; - -use libc::c_char; -use pgp::composed::{ - Deserializable, KeyType, SecretKeyParamsBuilder, SignedSecretKey, SubkeyParamsBuilder, -}; -use pgp::crypto::{HashAlgorithm, SymmetricKeyAlgorithm}; -use pgp::errors::Result; -use pgp::ser::Serialize; -use pgp::types::{CompressionAlgorithm, KeyTrait, SecretKeyTrait}; -use smallvec::smallvec; - -use crate::pgp::cvec; -use crate::pgp::signed_public_key; - -pub type signed_secret_key = SignedSecretKey; - -/// Generates a new RSA key. -pub unsafe fn rpgp_create_rsa_skey(bits: u32, user_id: *const c_char) -> *mut signed_secret_key { - assert!(!user_id.is_null()); - - let user_id = CStr::from_ptr(user_id); - let user_id_str = try_ffi!(user_id.to_str(), "invalid user id"); - - let key = try_ffi!( - create_key(KeyType::Rsa(bits), KeyType::Rsa(bits), user_id_str), - "failed to generate key" - ); - - Box::into_raw(Box::new(key)) -} - -/// Generates a new x25519 key. -#[allow(dead_code)] -pub unsafe fn rpgp_create_x25519_skey(user_id: *const c_char) -> *mut signed_secret_key { - assert!(!user_id.is_null()); - - let user_id = CStr::from_ptr(user_id); - let user_id_str = try_ffi!(user_id.to_str(), "invalid user id"); - let key = try_ffi!( - create_key(KeyType::EdDSA, KeyType::ECDH, user_id_str), - "failed to generate key" - ); - - Box::into_raw(Box::new(key)) -} - -/// Serialize a secret key into its byte representation. -pub unsafe fn rpgp_skey_to_bytes(skey_ptr: *mut signed_secret_key) -> *mut cvec { - assert!(!skey_ptr.is_null()); - - let skey = &*skey_ptr; - - let mut res = Vec::new(); - try_ffi!(skey.to_writer(&mut res), "failed to serialize key"); - - Box::into_raw(Box::new(res.into())) -} - -/// Get the signed public key matching the given private key. Only works for non password protected keys. -pub unsafe fn rpgp_skey_public_key(skey_ptr: *mut signed_secret_key) -> *mut signed_public_key { - assert!(!skey_ptr.is_null()); - - let skey = &*skey_ptr; - - let pkey = skey.public_key(); - let signed_pkey = try_ffi!(pkey.sign(&skey, || "".into()), "failed to sign key"); - - Box::into_raw(Box::new(signed_pkey)) -} - -/// Returns the KeyID for the passed in key. -#[allow(dead_code)] -pub unsafe fn rpgp_skey_key_id(skey_ptr: *mut signed_secret_key) -> *mut c_char { - assert!(!skey_ptr.is_null()); - - let key = &*skey_ptr; - let id = try_ffi!( - CString::new(hex::encode(&key.key_id())), - "failed to allocate string" - ); - - id.into_raw() -} - -/// Free the memory of a secret key. -pub unsafe fn rpgp_skey_drop(skey_ptr: *mut signed_secret_key) { - assert!(!skey_ptr.is_null()); - - let _skey = &*skey_ptr; - // Drop -} - -/// Creates an in-memory representation of a Secret PGP key, based on the serialized bytes given. -pub unsafe fn rpgp_skey_from_bytes(raw: *const u8, len: libc::size_t) -> *mut signed_secret_key { - assert!(!raw.is_null()); - assert!(len > 0); - - let bytes = slice::from_raw_parts(raw, len); - let key = try_ffi!( - SignedSecretKey::from_bytes(Cursor::new(bytes)), - "invalid secret key" - ); - try_ffi!(key.verify(), "failed to verify key"); - - Box::into_raw(Box::new(key)) -} - -fn create_key(typ: KeyType, sub_typ: KeyType, user_id: &str) -> Result { - let key_params = SecretKeyParamsBuilder::default() - .key_type(typ) - .can_create_certificates(true) - .can_sign(true) - .primary_user_id(user_id.into()) - .passphrase(None) - .preferred_symmetric_algorithms(smallvec![ - SymmetricKeyAlgorithm::AES256, - SymmetricKeyAlgorithm::AES192, - SymmetricKeyAlgorithm::AES128, - ]) - .preferred_hash_algorithms(smallvec![ - HashAlgorithm::SHA2_256, - HashAlgorithm::SHA2_384, - HashAlgorithm::SHA2_512, - HashAlgorithm::SHA2_224, - HashAlgorithm::SHA1, - ]) - .preferred_compression_algorithms(smallvec![ - CompressionAlgorithm::ZLIB, - CompressionAlgorithm::ZIP, - ]) - .subkey( - SubkeyParamsBuilder::default() - .key_type(sub_typ) - .can_encrypt(true) - .passphrase(None) - .build() - .unwrap(), - ) - .build()?; - - let key = key_params.generate()?; - - key.sign(|| "".into()) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::pgp::*; - use std::ffi::CStr; - use std::slice; - - use pgp::composed::{Deserializable, SignedPublicKey, SignedSecretKey}; - - #[test] - fn test_keygen_rsa() { - let user_id = CStr::from_bytes_with_nul(b"\0").unwrap(); - - unsafe { - /* Create the actual key */ - let skey = rpgp_create_rsa_skey(2048, user_id.as_ptr()); - - /* Serialize secret key into bytes */ - let skey_bytes = rpgp_skey_to_bytes(skey); - - /* Get the public key */ - let pkey = rpgp_skey_public_key(skey); - - /* Serialize public key into bytes */ - let pkey_bytes = rpgp_pkey_to_bytes(pkey); - - let skey_bytes_vec = - slice::from_raw_parts(rpgp_cvec_data(skey_bytes), rpgp_cvec_len(skey_bytes)); - let skey_back = - SignedSecretKey::from_bytes(skey_bytes_vec).expect("invalid secret key"); - assert_eq!(&*skey, &skey_back); - - let pkey_bytes_vec = - slice::from_raw_parts(rpgp_cvec_data(pkey_bytes), rpgp_cvec_len(pkey_bytes)); - let pkey_back = - SignedPublicKey::from_bytes(pkey_bytes_vec).expect("invalid public key"); - assert_eq!(&*pkey, &pkey_back); - - /* cleanup */ - rpgp_skey_drop(skey); - rpgp_cvec_drop(skey_bytes); - rpgp_pkey_drop(pkey); - rpgp_cvec_drop(pkey_bytes); - } - } -} diff --git a/tests/stress.rs b/tests/stress.rs index c63a852b2..6c156105f 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -2150,524 +2150,6 @@ unsafe fn stress_functions(context: &dc_context_t) { free(setupfile as *mut libc::c_void); free(setupcode as *mut libc::c_void); } - let bad_key: *mut dc_key_t = dc_key_new(); - let mut bad_data: [libc::c_uchar; 4096] = [0; 4096]; - let mut i_0: libc::c_int = 0i32; - while i_0 < 4096i32 { - bad_data[i_0 as usize] = (i_0 & 0xffi32) as libc::c_uchar; - i_0 += 1 - } - let mut j: libc::c_int = 0i32; - while j < 4096i32 / 40i32 { - dc_key_set_from_binary( - bad_key, - &mut *bad_data.as_mut_ptr().offset(j as isize) as *mut libc::c_uchar - as *const libc::c_void, - 4096i32 / 2i32 + j, - if 0 != j & 1i32 { 0i32 } else { 1i32 }, - ); - if 0 != (0 != dc_pgp_is_valid_key(context, bad_key)) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 941i32, - b"!dc_pgp_is_valid_key(context, bad_key)\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - j += 1 - } - dc_key_unref(bad_key); - let public_key: *mut dc_key_t = dc_key_new(); - let private_key: *mut dc_key_t = dc_key_new(); - dc_pgp_create_keypair( - context, - b"foo@bar.de\x00" as *const u8 as *const libc::c_char, - public_key, - private_key, - ); - if 0 != (0 == dc_pgp_is_valid_key(context, public_key)) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 949i32, - b"dc_pgp_is_valid_key(context, public_key)\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != (0 == dc_pgp_is_valid_key(context, private_key)) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 950i32, - b"dc_pgp_is_valid_key(context, private_key)\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - let test_key: *mut dc_key_t = dc_key_new(); - if 0 != (0 == dc_pgp_split_key(context, private_key, test_key)) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 956i32, - b"dc_pgp_split_key(context, private_key, test_key)\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - dc_key_unref(test_key); - let public_key2: *mut dc_key_t = dc_key_new(); - let private_key2: *mut dc_key_t = dc_key_new(); - dc_pgp_create_keypair( - context, - b"two@zwo.de\x00" as *const u8 as *const libc::c_char, - public_key2, - private_key2, - ); - if 0 != (0 != dc_key_equals(public_key, public_key2)) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 964i32, - b"!dc_key_equals(public_key, public_key2)\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - let original_text: *const libc::c_char = - b"This is a test\x00" as *const u8 as *const libc::c_char; - let mut ctext_signed: *mut libc::c_void = 0 as *mut libc::c_void; - let mut ctext_unsigned: *mut libc::c_void = 0 as *mut libc::c_void; - let mut ctext_signed_bytes: size_t = 0i32 as size_t; - let mut ctext_unsigned_bytes: size_t = 0; - let mut plain_bytes: size_t = 0i32 as size_t; - let keyring: *mut dc_keyring_t = dc_keyring_new(); - dc_keyring_add(keyring, public_key); - dc_keyring_add(keyring, public_key2); - let mut ok_0: libc::c_int = dc_pgp_pk_encrypt( - context, - original_text as *const libc::c_void, - strlen(original_text), - keyring, - private_key, - 1i32, - &mut ctext_signed as *mut *mut libc::c_void, - &mut ctext_signed_bytes, - ); - if 0 != !(0 != ok_0 && !ctext_signed.is_null() && ctext_signed_bytes > 0) as libc::c_int - as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 975i32, - b"ok && ctext_signed && ctext_signed_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - ctext_signed as *mut libc::c_char, - b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, - 27, - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 976i32, - b"strncmp((char*)ctext_signed, \"-----BEGIN PGP MESSAGE-----\", 27)==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - if 0 != !(*(ctext_signed as *mut libc::c_char) - .offset(ctext_signed_bytes.wrapping_sub(1) as isize) as libc::c_int - != 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 977i32, - b"((char*)ctext_signed)[ctext_signed_bytes-1]!=0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - ok_0 = dc_pgp_pk_encrypt( - context, - original_text as *const libc::c_void, - strlen(original_text), - keyring, - 0 as *const dc_key_t, - 1i32, - &mut ctext_unsigned as *mut *mut libc::c_void, - &mut ctext_unsigned_bytes, - ); - if 0 != !(0 != ok_0 && !ctext_unsigned.is_null() && ctext_unsigned_bytes > 0) as libc::c_int - as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 981i32, - b"ok && ctext_unsigned && ctext_unsigned_bytes>0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - ctext_unsigned as *mut libc::c_char, - b"-----BEGIN PGP MESSAGE-----\x00" as *const u8 as *const libc::c_char, - 27, - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 982i32, - b"strncmp((char*)ctext_unsigned, \"-----BEGIN PGP MESSAGE-----\", 27)==0\x00" - as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(ctext_unsigned_bytes < ctext_signed_bytes) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 983i32, - b"ctext_unsigned_bytes < ctext_signed_bytes\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - dc_keyring_unref(keyring); - let keyring_0: *mut dc_keyring_t = dc_keyring_new(); - dc_keyring_add(keyring_0, private_key); - let public_keyring: *mut dc_keyring_t = dc_keyring_new(); - dc_keyring_add(public_keyring, public_key); - let public_keyring2: *mut dc_keyring_t = dc_keyring_new(); - dc_keyring_add(public_keyring2, public_key2); - let mut plain_0: *mut libc::c_void = 0 as *mut libc::c_void; - let mut valid_signatures: dc_hash_t = dc_hash_t { - keyClass: 0, - copyKey: 0, - count: 0, - first: 0 as *mut dc_hashelem_t, - htsize: 0, - ht: 0 as *mut _ht, - }; - dc_hash_init(&mut valid_signatures, 3i32, 1i32); - let mut ok_1: libc::c_int; - ok_1 = dc_pgp_pk_decrypt( - context, - ctext_signed, - ctext_signed_bytes, - keyring_0, - public_keyring, - 1i32, - &mut plain_0, - &mut plain_bytes, - &mut valid_signatures, - ); - if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1004i32, - b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - plain_0 as *mut libc::c_char, - original_text, - strlen(original_text), - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1005i32, - b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - if 0 != !(valid_signatures.count == 1i32) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1006i32, - b"dc_hash_cnt(&valid_signatures) == 1\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - free(plain_0); - plain_0 = 0 as *mut libc::c_void; - dc_hash_clear(&mut valid_signatures); - ok_1 = dc_pgp_pk_decrypt( - context, - ctext_signed, - ctext_signed_bytes, - keyring_0, - 0 as *const dc_keyring_t, - 1i32, - &mut plain_0, - &mut plain_bytes, - &mut valid_signatures, - ); - if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1011i32, - b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - plain_0 as *mut libc::c_char, - original_text, - strlen(original_text), - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1012i32, - b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - if 0 != !(valid_signatures.count == 0i32) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1013i32, - b"dc_hash_cnt(&valid_signatures) == 0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - free(plain_0); - plain_0 = 0 as *mut libc::c_void; - dc_hash_clear(&mut valid_signatures); - ok_1 = dc_pgp_pk_decrypt( - context, - ctext_signed, - ctext_signed_bytes, - keyring_0, - public_keyring2, - 1i32, - &mut plain_0, - &mut plain_bytes, - &mut valid_signatures, - ); - if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1018i32, - b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - plain_0 as *mut libc::c_char, - original_text, - strlen(original_text), - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1019i32, - b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - if 0 != !(valid_signatures.count == 0i32) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1020i32, - b"dc_hash_cnt(&valid_signatures) == 0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - free(plain_0); - plain_0 = 0 as *mut libc::c_void; - dc_hash_clear(&mut valid_signatures); - dc_keyring_add(public_keyring2, public_key); - ok_1 = dc_pgp_pk_decrypt( - context, - ctext_signed, - ctext_signed_bytes, - keyring_0, - public_keyring2, - 1i32, - &mut plain_0, - &mut plain_bytes, - &mut valid_signatures, - ); - if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1026i32, - b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - plain_0 as *mut libc::c_char, - original_text, - strlen(original_text), - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1027i32, - b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - if 0 != !(valid_signatures.count == 1i32) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1028i32, - b"dc_hash_cnt(&valid_signatures) == 1\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - free(plain_0); - plain_0 = 0 as *mut libc::c_void; - dc_hash_clear(&mut valid_signatures); - ok_1 = dc_pgp_pk_decrypt( - context, - ctext_unsigned, - ctext_unsigned_bytes, - keyring_0, - public_keyring, - 1i32, - &mut plain_0, - &mut plain_bytes, - &mut valid_signatures, - ); - if 0 != !(0 != ok_1 && !plain_0.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1033i32, - b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp( - plain_0 as *mut libc::c_char, - original_text, - strlen(original_text), - ) == 0i32) as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1034i32, - b"strncmp((char*)plain, original_text, strlen(original_text))==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - free(plain_0); - dc_hash_clear(&mut valid_signatures); - dc_keyring_unref(keyring_0); - dc_keyring_unref(public_keyring); - dc_keyring_unref(public_keyring2); - let keyring_1: *mut dc_keyring_t = dc_keyring_new(); - dc_keyring_add(keyring_1, private_key2); - let public_keyring_0: *mut dc_keyring_t = dc_keyring_new(); - dc_keyring_add(public_keyring_0, public_key); - let mut plain_1: *mut libc::c_void = 0 as *mut libc::c_void; - let ok_2: libc::c_int = dc_pgp_pk_decrypt( - context, - ctext_signed, - ctext_signed_bytes, - keyring_1, - public_keyring_0, - 1i32, - &mut plain_1, - &mut plain_bytes, - 0 as *mut dc_hash_t, - ); - if 0 != !(0 != ok_2 && !plain_1.is_null() && plain_bytes > 0) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1053i32, - b"ok && plain && plain_bytes>0\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(plain_bytes == strlen(original_text)) as libc::c_int as libc::c_long { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1054i32, - b"plain_bytes == strlen(original_text)\x00" as *const u8 as *const libc::c_char, - ); - } else { - }; - if 0 != !(strncmp(plain_1 as *const libc::c_char, original_text, plain_bytes) == 0i32) - as libc::c_int as libc::c_long - { - __assert_rtn( - (*::std::mem::transmute::<&[u8; 17], &[libc::c_char; 17]>(b"stress_functions\x00")) - .as_ptr(), - b"../cmdline/stress.c\x00" as *const u8 as *const libc::c_char, - 1055i32, - b"strncmp(plain, original_text, plain_bytes)==0\x00" as *const u8 - as *const libc::c_char, - ); - } else { - }; - free(plain_1); - dc_keyring_unref(keyring_1); - dc_keyring_unref(public_keyring_0); - free(ctext_signed); - free(ctext_unsigned); - dc_key_unref(public_key2); - dc_key_unref(private_key2); - dc_key_unref(public_key); - dc_key_unref(private_key); if 0 != dc_is_configured(context) { let qr: *mut libc::c_char = dc_get_securejoin_qr(context, 0i32 as uint32_t); @@ -2753,6 +2235,197 @@ unsafe fn stress_functions(context: &dc_context_t) { }; } +#[test] +fn test_encryption_decryption() { + unsafe { + let mut bad_data: [libc::c_uchar; 4096] = [0; 4096]; + let mut i_0: libc::c_int = 0i32; + while i_0 < 4096i32 { + bad_data[i_0 as usize] = (i_0 & 0xffi32) as libc::c_uchar; + i_0 += 1 + } + let mut j: libc::c_int = 0i32; + + while j < 4096 / 40 { + let bad_key = Key::from_binary( + &mut *bad_data.as_mut_ptr().offset(j as isize) as *mut libc::c_uchar + as *const libc::c_void, + 4096 / 2 + j, + if 0 != j & 1 { + KeyType::Public + } else { + KeyType::Private + }, + ); + + assert!(bad_key.is_none()); + j += 1 + } + + let (public_key, private_key) = + dc_pgp_create_keypair(b"foo@bar.de\x00" as *const u8 as *const libc::c_char).unwrap(); + + private_key.split_key().unwrap(); + + let (public_key2, private_key2) = + dc_pgp_create_keypair(b"two@zwo.de\x00" as *const u8 as *const libc::c_char).unwrap(); + + assert_ne!(public_key, public_key2); + + let original_text: *const libc::c_char = + b"This is a test\x00" as *const u8 as *const libc::c_char; + let mut keyring = Keyring::default(); + keyring.add(public_key.clone()); + keyring.add(public_key2.clone()); + + let ctext = dc_pgp_pk_encrypt( + original_text as *const libc::c_void, + strlen(original_text), + &keyring, + Some(&private_key), + ) + .unwrap(); + + assert!(!ctext.is_empty()); + assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----")); + + let ctext_signed_bytes = ctext.len(); + let ctext_signed = CString::new(ctext).unwrap(); + + let ctext = dc_pgp_pk_encrypt( + original_text as *const libc::c_void, + strlen(original_text), + &keyring, + None, + ) + .unwrap(); + assert!(!ctext.is_empty()); + assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----")); + + let ctext_unsigned_bytes = ctext.len(); + let ctext_unsigned = CString::new(ctext).unwrap(); + + let mut keyring = Keyring::default(); + keyring.add(private_key); + + let mut public_keyring = Keyring::default(); + public_keyring.add(public_key.clone()); + + let mut public_keyring2 = Keyring::default(); + public_keyring2.add(public_key2.clone()); + + let mut valid_signatures = dc_hash_t { + keyClass: 0, + copyKey: 0, + count: 0, + first: 0 as *mut dc_hashelem_t, + htsize: 0, + ht: 0 as *mut _ht, + }; + dc_hash_init(&mut valid_signatures, 3i32, 1i32); + + let plain = dc_pgp_pk_decrypt( + ctext_signed.as_ptr() as *const _, + ctext_signed_bytes, + &keyring, + &public_keyring, + &mut valid_signatures, + ) + .unwrap(); + + assert_eq!( + std::str::from_utf8(&plain).unwrap(), + CStr::from_ptr(original_text).to_str().unwrap() + ); + assert_eq!(valid_signatures.count, 1); + + dc_hash_clear(&mut valid_signatures); + + let empty_keyring = Keyring::default(); + let plain = dc_pgp_pk_decrypt( + ctext_signed.as_ptr() as *const _, + ctext_signed_bytes, + &keyring, + &empty_keyring, + &mut valid_signatures, + ) + .unwrap(); + assert_eq!( + std::str::from_utf8(&plain).unwrap(), + CStr::from_ptr(original_text).to_str().unwrap() + ); + assert_eq!(valid_signatures.count, 0); + + dc_hash_clear(&mut valid_signatures); + + let plain = dc_pgp_pk_decrypt( + ctext_signed.as_ptr() as *const _, + ctext_signed_bytes, + &keyring, + &public_keyring2, + &mut valid_signatures, + ) + .unwrap(); + assert_eq!( + std::str::from_utf8(&plain).unwrap(), + CStr::from_ptr(original_text).to_str().unwrap() + ); + assert_eq!(valid_signatures.count, 0); + + dc_hash_clear(&mut valid_signatures); + + public_keyring2.add(public_key.clone()); + + let plain = dc_pgp_pk_decrypt( + ctext_signed.as_ptr() as *const _, + ctext_signed_bytes, + &keyring, + &public_keyring2, + &mut valid_signatures, + ) + .unwrap(); + assert_eq!( + std::str::from_utf8(&plain).unwrap(), + CStr::from_ptr(original_text).to_str().unwrap() + ); + assert_eq!(valid_signatures.count, 1); + + dc_hash_clear(&mut valid_signatures); + let plain = dc_pgp_pk_decrypt( + ctext_unsigned.as_ptr() as *const _, + ctext_unsigned_bytes, + &keyring, + &public_keyring, + &mut valid_signatures, + ) + .unwrap(); + assert_eq!( + std::str::from_utf8(&plain).unwrap(), + CStr::from_ptr(original_text).to_str().unwrap() + ); + + dc_hash_clear(&mut valid_signatures); + + let mut keyring = Keyring::default(); + keyring.add(private_key2); + let mut public_keyring = Keyring::default(); + public_keyring.add(public_key); + + let plain = dc_pgp_pk_decrypt( + ctext_signed.as_ptr() as *const _, + ctext_signed_bytes, + &keyring, + &public_keyring, + 0 as *mut dc_hash_t, + ) + .unwrap(); + assert_eq!( + std::str::from_utf8(&plain).unwrap(), + CStr::from_ptr(original_text).to_str().unwrap() + ); + } +} + unsafe extern "C" fn cb( _context: &dc_context_t, _event: Event,