perf: reduce verification load (#75)

- assume valid keys in the db
- verify keys on import from headers + disk
- use references in keyring when possible
This commit is contained in:
Friedel Ziegelmayer
2019-05-17 10:19:43 +02:00
committed by Lars-Magnus Skog
parent 8678813051
commit 379fc72094
7 changed files with 54 additions and 36 deletions

View File

@@ -160,7 +160,13 @@ impl str::FromStr for Aheader {
.remove("keydata") .remove("keydata")
.and_then(|raw| Key::from_base64(&raw, KeyType::Public)) .and_then(|raw| Key::from_base64(&raw, KeyType::Public))
{ {
Some(key) => key, Some(key) => {
if key.verify() {
key
} else {
return Err(());
}
}
None => { None => {
return Err(()); return Err(());
} }

View File

@@ -121,11 +121,9 @@ pub unsafe fn dc_e2ee_encrypt(
recipient_addr, recipient_addr,
) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed) ) && (peerstate.prefer_encrypt == 1i32 || 0 != e2ee_guaranteed)
{ {
if let Some(key_to_use) = if let Some(key) = dc_apeerstate_peek_key(&peerstate, min_verified)
dc_apeerstate_peek_key(&peerstate, min_verified)
{ {
// TODO: avoid clone keyring.add_owned(key.clone());
keyring.add(key_to_use.clone());
peerstates.push(peerstate); peerstates.push(peerstate);
} }
} else { } else {
@@ -143,8 +141,7 @@ pub unsafe fn dc_e2ee_encrypt(
} }
} }
let sign_key = if 0 != do_encrypt { let sign_key = if 0 != do_encrypt {
// TODO: avoid clone keyring.add_ref(&public_key);
keyring.add(public_key.clone());
let key = let key =
Key::from_self_private(context, addr, &context.sql.clone().read().unwrap()); Key::from_self_private(context, addr, &context.sql.clone().read().unwrap());
@@ -670,12 +667,11 @@ pub unsafe fn dc_e2ee_decrypt(
if 0 != peerstate.degrade_event { if 0 != peerstate.degrade_event {
dc_handle_degrade_event(context, &peerstate); dc_handle_degrade_event(context, &peerstate);
} }
// TODO: avoid clone
if let Some(ref key) = peerstate.gossip_key { if let Some(ref key) = peerstate.gossip_key {
public_keyring_for_validate.add(key.clone()); public_keyring_for_validate.add_ref(key);
} }
if let Some(ref key) = peerstate.public_key { if let Some(ref key) = peerstate.public_key {
public_keyring_for_validate.add(key.clone()); public_keyring_for_validate.add_ref(key);
} }
(*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t; (*helper).signatures = malloc(::std::mem::size_of::<dc_hash_t>()) as *mut dc_hash_t;
dc_hash_init((*helper).signatures, 3i32, 1i32); dc_hash_init((*helper).signatures, 3i32, 1i32);

View File

@@ -522,6 +522,7 @@ unsafe fn set_self_key(
CStr::from_ptr(buf_base64).to_str().unwrap(), CStr::from_ptr(buf_base64).to_str().unwrap(),
KeyType::Private, KeyType::Private,
) )
.and_then(|k| if k.verify() { Some(k) } else { None })
.and_then(|k| k.split_key().map(|pub_key| (k, pub_key))) .and_then(|k| k.split_key().map(|pub_key| (k, pub_key)))
{ {
stmt = dc_sqlite3_prepare( stmt = dc_sqlite3_prepare(

View File

@@ -97,14 +97,7 @@ impl Key {
}; };
match res { match res {
Ok(key) => { Ok(key) => Some(key),
if key.verify() {
Some(key)
} else {
eprintln!("Invalid key: {:?}", key);
None
}
}
Err(err) => { Err(err) => {
eprintln!("Invalid key bytes: {:?}\n{}", err, hex::encode(bytes)); eprintln!("Invalid key bytes: {:?}\n{}", err, hex::encode(bytes));
None None

View File

@@ -1,3 +1,5 @@
use std::borrow::Cow;
use crate::constants::*; use crate::constants::*;
use crate::dc_context::dc_context_t; use crate::dc_context::dc_context_t;
use crate::dc_key::*; use crate::dc_key::*;
@@ -5,16 +7,24 @@ use crate::dc_sqlite3::*;
use crate::types::*; use crate::types::*;
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
pub struct Keyring { pub struct Keyring<'a> {
keys: Vec<Key>, keys: Vec<Cow<'a, Key>>,
} }
impl Keyring { impl<'a> Keyring<'a> {
pub fn add(&mut self, key: Key) { pub fn add_owned(&mut self, key: Key) {
self.add(Cow::Owned(key))
}
pub fn add_ref(&mut self, key: &'a Key) {
self.add(Cow::Borrowed(key))
}
fn add(&mut self, key: Cow<'a, Key>) {
self.keys.push(key); self.keys.push(key);
} }
pub fn keys(&self) -> &[Key] { pub fn keys(&self) -> &[Cow<'a, Key>] {
&self.keys &self.keys
} }
@@ -39,7 +49,7 @@ impl Keyring {
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) }; unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
while unsafe { sqlite3_step(stmt) == 100 } { while unsafe { sqlite3_step(stmt) == 100 } {
if let Some(key) = Key::from_stmt(stmt, 0, KeyType::Private) { if let Some(key) = Key::from_stmt(stmt, 0, KeyType::Private) {
self.add(key); self.add_owned(key);
} }
} }
unsafe { sqlite3_finalize(stmt) }; unsafe { sqlite3_finalize(stmt) };

View File

@@ -182,6 +182,9 @@ pub fn dc_pgp_create_keypair(addr: *const libc::c_char) -> Option<(Key, Key)> {
.sign(&private_key, || "".into()) .sign(&private_key, || "".into())
.expect("failed to sign public key"); .expect("failed to sign public key");
private_key.verify().expect("invalid private key generated");
public_key.verify().expect("invalid public key generated");
Some((Key::Public(public_key), Key::Secret(private_key))) Some((Key::Public(public_key), Key::Secret(private_key)))
} }
@@ -197,8 +200,11 @@ pub fn dc_pgp_pk_encrypt(
let lit_msg = Message::new_literal_bytes("", bytes); let lit_msg = Message::new_literal_bytes("", bytes);
let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption
.keys() .keys()
.iter() .into_iter()
.filter_map(|key| key.try_into().ok()) .filter_map(|key| {
let k: &Key = &key;
k.try_into().ok()
})
.collect(); .collect();
let mut rng = thread_rng(); let mut rng = thread_rng();
@@ -237,7 +243,10 @@ pub fn dc_pgp_pk_decrypt(
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
.keys() .keys()
.iter() .iter()
.filter_map(|key| key.try_into().ok()) .filter_map(|key| {
let k: &Key = &key;
k.try_into().ok()
})
.collect(); .collect();
msg.decrypt(|| "".into(), || "".into(), &skeys[..]) msg.decrypt(|| "".into(), || "".into(), &skeys[..])
@@ -252,7 +261,10 @@ pub fn dc_pgp_pk_decrypt(
let pkeys: Vec<&SignedPublicKey> = public_keys_for_validation let pkeys: Vec<&SignedPublicKey> = public_keys_for_validation
.keys() .keys()
.iter() .iter()
.filter_map(|key| key.try_into().ok()) .filter_map(|key| {
let k: &Key = &key;
k.try_into().ok()
})
.collect(); .collect();
for pkey in &pkeys { for pkey in &pkeys {

View File

@@ -2239,8 +2239,8 @@ fn test_encryption_decryption() {
let original_text: *const libc::c_char = let original_text: *const libc::c_char =
b"This is a test\x00" as *const u8 as *const libc::c_char; b"This is a test\x00" as *const u8 as *const libc::c_char;
let mut keyring = Keyring::default(); let mut keyring = Keyring::default();
keyring.add(public_key.clone()); keyring.add_owned(public_key.clone());
keyring.add(public_key2.clone()); keyring.add_ref(&public_key2);
let ctext = dc_pgp_pk_encrypt( let ctext = dc_pgp_pk_encrypt(
original_text as *const libc::c_void, original_text as *const libc::c_void,
@@ -2270,13 +2270,13 @@ fn test_encryption_decryption() {
let ctext_unsigned = CString::new(ctext).unwrap(); let ctext_unsigned = CString::new(ctext).unwrap();
let mut keyring = Keyring::default(); let mut keyring = Keyring::default();
keyring.add(private_key); keyring.add_owned(private_key);
let mut public_keyring = Keyring::default(); let mut public_keyring = Keyring::default();
public_keyring.add(public_key.clone()); public_keyring.add_ref(&public_key);
let mut public_keyring2 = Keyring::default(); let mut public_keyring2 = Keyring::default();
public_keyring2.add(public_key2.clone()); public_keyring2.add_owned(public_key2.clone());
let mut valid_signatures = dc_hash_t { let mut valid_signatures = dc_hash_t {
keyClass: 0, keyClass: 0,
@@ -2338,7 +2338,7 @@ fn test_encryption_decryption() {
dc_hash_clear(&mut valid_signatures); dc_hash_clear(&mut valid_signatures);
public_keyring2.add(public_key.clone()); public_keyring2.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed.as_ptr() as *const _, ctext_signed.as_ptr() as *const _,
@@ -2371,9 +2371,9 @@ fn test_encryption_decryption() {
dc_hash_clear(&mut valid_signatures); dc_hash_clear(&mut valid_signatures);
let mut keyring = Keyring::default(); let mut keyring = Keyring::default();
keyring.add(private_key2); keyring.add_ref(&private_key2);
let mut public_keyring = Keyring::default(); let mut public_keyring = Keyring::default();
public_keyring.add(public_key); public_keyring.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt( let plain = dc_pgp_pk_decrypt(
ctext_signed.as_ptr() as *const _, ctext_signed.as_ptr() as *const _,