use rpgp directly

This commit is contained in:
dignifiedquire
2019-04-26 21:58:58 +03:00
parent ff1d0ca445
commit 29993db512
16 changed files with 1143 additions and 204 deletions

View File

@@ -4,6 +4,7 @@ version = "0.1.0"
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
edition = "2018"
[build-dependencies]
cc = "1.0.35"
pkg-config = "0.3"
@@ -12,3 +13,9 @@ bindgen = "0.49.0"
[dependencies]
c2rust-bitfields = "0.1.0"
libc = "0.2.51"
pgp = "0.2.0"
failure = "0.1.5"
hex = "0.3.2"
sha2 = "0.8.0"
rand = "0.6.5"
smallvec = "0.6.9"

View File

@@ -21,7 +21,6 @@ fn main() {
println!("cargo:rustc-link-lib=dylib=sqlite3");
println!("cargo:rustc-link-lib=dylib=pthread");
println!("cargo:rustc-link-lib=dylib=rpgp");
println!("cargo:rustc-link-lib=dylib=crypto");
println!("cargo:rustc-link-lib=dylib=tools");

View File

@@ -9,27 +9,10 @@ use crate::dc_log::*;
use crate::dc_lot::dc_lot_t;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::pgp as rpgp;
use crate::types::*;
use crate::x::*;
pub type rpgp_signed_secret_key = rpgp_SignedSecretKey;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct rpgp_cvec {
pub data: *mut uint8_t,
pub len: size_t,
}
pub type rpgp_message = rpgp_Message;
pub type rpgp_signed_public_key = rpgp_SignedPublicKey;
pub type rpgp_public_or_secret_key = rpgp_PublicOrSecret;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct rpgp_message_decrypt_result {
pub message_ptr: *mut rpgp_message,
pub valid_ids_ptr: *mut *mut libc::c_char,
pub valid_ids_len: size_t,
}
/* ** library-private **********************************************************/
/* validation errors */
/* misc. */
@@ -171,31 +154,31 @@ pub unsafe extern "C" fn dc_pgp_create_keypair(
mut ret_private_key: *mut dc_key_t,
) -> libc::c_int {
let mut success: libc::c_int = 0i32;
let mut skey: *mut rpgp_signed_secret_key = 0 as *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 mut skey: *mut rpgp::signed_secret_key = 0 as *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 mut user_id: *mut libc::c_char = 0 as *mut libc::c_char;
user_id = dc_mprintf(b"<%s>\x00" as *const u8 as *const libc::c_char, addr);
skey = rpgp_create_rsa_skey(2048i32 as uint32_t, user_id);
skey = rpgp::rpgp_create_rsa_skey(2048i32 as uint32_t, user_id);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
skey_bytes = rpgp_skey_to_bytes(skey);
skey_bytes = rpgp::rpgp_skey_to_bytes(skey);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
pkey = rpgp_skey_public_key(skey);
pkey = rpgp::rpgp_skey_public_key(skey);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
pkey_bytes = rpgp_pkey_to_bytes(pkey);
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_cvec_data(skey_bytes) as *const libc::c_void,
rpgp_cvec_len(skey_bytes) as libc::c_int,
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_cvec_data(pkey_bytes) as *const libc::c_void,
rpgp_cvec_len(pkey_bytes) as libc::c_int,
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)) {
@@ -208,16 +191,16 @@ pub unsafe extern "C" fn dc_pgp_create_keypair(
}
/* cleanup */
if !skey.is_null() {
rpgp_skey_drop(skey);
rpgp::rpgp_skey_drop(skey);
}
if !skey_bytes.is_null() {
rpgp_cvec_drop(skey_bytes);
rpgp::rpgp_cvec_drop(skey_bytes);
}
if !pkey.is_null() {
rpgp_pkey_drop(pkey);
rpgp::rpgp_pkey_drop(pkey);
}
if !pkey_bytes.is_null() {
rpgp_cvec_drop(pkey_bytes);
rpgp::rpgp_cvec_drop(pkey_bytes);
}
if !user_id.is_null() {
free(user_id as *mut libc::c_void);
@@ -230,9 +213,9 @@ pub unsafe extern "C" fn dc_pgp_handle_rpgp_error(mut context: *mut dc_context_t
let mut success: libc::c_int = 0i32;
let mut len: libc::c_int = 0i32;
let mut msg: *mut libc::c_char = 0 as *mut libc::c_char;
len = rpgp_last_error_length();
len = rpgp::rpgp_last_error_length();
if !(len == 0i32) {
msg = rpgp_last_error_message();
msg = rpgp::rpgp_last_error_message();
if !context.is_null() {
dc_log_info(
context,
@@ -244,7 +227,7 @@ pub unsafe extern "C" fn dc_pgp_handle_rpgp_error(mut context: *mut dc_context_t
success = 1i32
}
if !msg.is_null() {
rpgp_string_drop(msg);
rpgp::rpgp_string_drop(msg);
}
return success;
}
@@ -254,26 +237,27 @@ pub unsafe extern "C" fn dc_pgp_is_valid_key(
mut 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;
let mut key: *mut rpgp::public_or_secret_key = 0 as *mut rpgp::public_or_secret_key;
if !(context.is_null()
|| raw_key.is_null()
|| (*raw_key).binary.is_null()
|| (*raw_key).bytes <= 0i32)
{
key = rpgp_key_from_bytes(
key = rpgp::rpgp_key_from_bytes(
(*raw_key).binary as *const uint8_t,
(*raw_key).bytes as size_t,
(*raw_key).bytes as usize,
);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
if (*raw_key).type_0 == 0i32 && 0 != rpgp_key_is_public(key) as libc::c_int {
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_key_is_secret(key) as libc::c_int {
} 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_key_drop(key);
rpgp::rpgp_key_drop(key);
}
return key_is_valid;
}
@@ -284,8 +268,8 @@ pub unsafe extern "C" fn dc_pgp_calc_fingerprint(
mut 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;
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()
@@ -294,18 +278,18 @@ pub unsafe extern "C" fn dc_pgp_calc_fingerprint(
|| (*raw_key).binary.is_null()
|| (*raw_key).bytes <= 0i32)
{
key = rpgp_key_from_bytes(
key = rpgp::rpgp_key_from_bytes(
(*raw_key).binary as *const uint8_t,
(*raw_key).bytes as size_t,
(*raw_key).bytes as usize,
);
if !(0 != dc_pgp_handle_rpgp_error(0 as *mut dc_context_t)) {
fingerprint = rpgp_key_fingerprint(key);
fingerprint = rpgp::rpgp_key_fingerprint(key);
if !(0 != dc_pgp_handle_rpgp_error(0 as *mut dc_context_t)) {
*ret_fingerprint_bytes = rpgp_cvec_len(fingerprint);
*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_cvec_data(fingerprint) as *const libc::c_void,
rpgp::rpgp_cvec_data(fingerprint) as *const libc::c_void,
*ret_fingerprint_bytes,
);
success = 1i32
@@ -313,10 +297,10 @@ pub unsafe extern "C" fn dc_pgp_calc_fingerprint(
}
}
if !key.is_null() {
rpgp_key_drop(key);
rpgp::rpgp_key_drop(key);
}
if !fingerprint.is_null() {
rpgp_cvec_drop(fingerprint);
rpgp::rpgp_cvec_drop(fingerprint);
}
return success;
}
@@ -327,9 +311,9 @@ pub unsafe extern "C" fn dc_pgp_split_key(
mut ret_public_key: *mut dc_key_t,
) -> libc::c_int {
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;
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 !(context.is_null() || private_in.is_null() || ret_public_key.is_null()) {
if (*private_in).type_0 != 1i32 {
dc_log_warning(
@@ -338,19 +322,19 @@ pub unsafe extern "C" fn dc_pgp_split_key(
b"Split key: Given key is no private key.\x00" as *const u8 as *const libc::c_char,
);
} else {
key = rpgp_skey_from_bytes(
key = rpgp::rpgp_skey_from_bytes(
(*private_in).binary as *const uint8_t,
(*private_in).bytes as size_t,
(*private_in).bytes as usize,
);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
pub_key = rpgp_skey_public_key(key);
pub_key = rpgp::rpgp_skey_public_key(key);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
buf = rpgp_pkey_to_bytes(pub_key);
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_cvec_data(buf) as *const libc::c_void,
rpgp_cvec_len(buf) as libc::c_int,
rpgp::rpgp_cvec_data(buf) as *const libc::c_void,
rpgp::rpgp_cvec_len(buf) as libc::c_int,
0i32,
);
success = 1i32
@@ -360,13 +344,13 @@ pub unsafe extern "C" fn dc_pgp_split_key(
}
}
if !key.is_null() {
rpgp_skey_drop(key);
rpgp::rpgp_skey_drop(key);
}
if !pub_key.is_null() {
rpgp_pkey_drop(pub_key);
rpgp::rpgp_pkey_drop(pub_key);
}
if !buf.is_null() {
rpgp_cvec_drop(buf);
rpgp::rpgp_cvec_drop(buf);
}
return success;
}
@@ -385,9 +369,9 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
let mut i: libc::c_int = 0i32;
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;
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 !(context.is_null()
|| plain_text == 0 as *mut libc::c_void
|| plain_bytes == 0i32 as libc::c_ulong
@@ -402,14 +386,14 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
*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>() as libc::c_ulong)
(::std::mem::size_of::<*mut rpgp::signed_public_key>() as libc::c_ulong)
.wrapping_mul(public_keys_len as libc::c_ulong),
) as *mut *mut rpgp_signed_public_key;
) as *mut *mut rpgp::signed_public_key;
/* setup secret key for signing */
if !raw_private_key_for_signing.is_null() {
private_key = rpgp_skey_from_bytes(
private_key = rpgp::rpgp_skey_from_bytes(
(*raw_private_key_for_signing).binary as *const uint8_t,
(*raw_private_key_for_signing).bytes as size_t,
(*raw_private_key_for_signing).bytes as usize,
);
if private_key.is_null() || 0 != dc_pgp_handle_rpgp_error(context) {
dc_log_warning(
@@ -435,11 +419,11 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
break;
}
let ref mut fresh0 = *public_keys.offset(i as isize);
*fresh0 = rpgp_pkey_from_bytes(
*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 size_t,
as usize,
);
if 0 != dc_pgp_handle_rpgp_error(context) {
current_block = 2132137392766895896;
@@ -454,11 +438,11 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
let mut op_clocks: libc::clock_t = 0i32 as libc::clock_t;
let mut start: libc::clock_t = clock();
if private_key.is_null() {
encrypted = rpgp_encrypt_bytes_to_keys(
encrypted = rpgp::rpgp_encrypt_bytes_to_keys(
plain_text as *const uint8_t,
plain_bytes,
public_keys as *const *const rpgp_signed_public_key,
public_keys_len as size_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(
@@ -480,11 +464,11 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
current_block = 1538046216550696469;
}
} else {
encrypted = rpgp_sign_encrypt_bytes_to_keys(
encrypted = rpgp::rpgp_sign_encrypt_bytes_to_keys(
plain_text as *const uint8_t,
plain_bytes,
public_keys as *const *const rpgp_signed_public_key,
public_keys_len as size_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) {
@@ -512,10 +496,11 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
2132137392766895896 => {}
_ => {
/* convert message to armored bytes and return values */
let mut armored: *mut rpgp_cvec = rpgp_msg_to_armored(encrypted);
let mut armored: *mut rpgp::cvec =
rpgp::rpgp_msg_to_armored(encrypted);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
*ret_ctext = rpgp_cvec_data(armored) as *mut libc::c_void;
*ret_ctext_bytes = rpgp_cvec_len(armored);
*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
}
@@ -527,15 +512,15 @@ pub unsafe extern "C" fn dc_pgp_pk_encrypt(
}
}
if !private_key.is_null() {
rpgp_skey_drop(private_key);
rpgp::rpgp_skey_drop(private_key);
}
i = 0i32;
while i < public_keys_len {
rpgp_pkey_drop(*public_keys.offset(i as isize));
rpgp::rpgp_pkey_drop(*public_keys.offset(i as isize));
i += 1
}
if !encrypted.is_null() {
rpgp_msg_drop(encrypted);
rpgp::rpgp_msg_drop(encrypted);
}
return success;
}
@@ -554,12 +539,13 @@ pub unsafe extern "C" fn dc_pgp_pk_decrypt(
let mut current_block: u64;
let mut i: libc::c_int = 0i32;
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 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;
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 !(context.is_null()
|| ctext == 0 as *mut libc::c_void
|| ctext_bytes == 0i32 as libc::c_ulong
@@ -574,15 +560,15 @@ pub unsafe extern "C" fn dc_pgp_pk_decrypt(
*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>() as libc::c_ulong)
(::std::mem::size_of::<*mut rpgp::signed_secret_key>() as libc::c_ulong)
.wrapping_mul(private_keys_len as libc::c_ulong),
) as *mut *mut rpgp_signed_secret_key;
) 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>() as libc::c_ulong)
(::std::mem::size_of::<*mut rpgp::signed_public_key>() as libc::c_ulong)
.wrapping_mul(public_keys_len as libc::c_ulong),
) as *mut *mut rpgp_signed_public_key
) as *mut *mut rpgp::signed_public_key
}
/* setup secret keys for decryption */
i = 0i32;
@@ -592,10 +578,10 @@ pub unsafe extern "C" fn dc_pgp_pk_decrypt(
break;
}
let ref mut fresh1 = *private_keys.offset(i as isize);
*fresh1 = rpgp_skey_from_bytes(
*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 size_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;
@@ -615,11 +601,11 @@ pub unsafe extern "C" fn dc_pgp_pk_decrypt(
break;
}
let ref mut fresh2 = *public_keys.offset(i as isize);
*fresh2 = rpgp_pkey_from_bytes(
*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 size_t,
as usize,
);
if 0 != dc_pgp_handle_rpgp_error(context) {
current_block = 11904635156640512504;
@@ -634,22 +620,26 @@ pub unsafe extern "C" fn dc_pgp_pk_decrypt(
11904635156640512504 => {}
_ => {
/* decrypt */
encrypted = rpgp_msg_from_armor(ctext as *const uint8_t, ctext_bytes);
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_msg_decrypt_no_pw(
decrypted = rpgp::rpgp_msg_decrypt_no_pw(
encrypted,
private_keys as *const *const rpgp_signed_secret_key,
private_keys_len as size_t,
public_keys as *const *const rpgp_signed_public_key,
public_keys_len as size_t,
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 mut decrypted_bytes: *mut rpgp_cvec =
rpgp_msg_to_bytes((*decrypted).message_ptr);
let mut 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_cvec_len(decrypted_bytes);
*ret_plain_bytes =
rpgp::rpgp_cvec_len(decrypted_bytes) as size_t;
*ret_plain =
rpgp_cvec_data(decrypted_bytes) as *mut libc::c_void;
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;
@@ -681,19 +671,19 @@ pub unsafe extern "C" fn dc_pgp_pk_decrypt(
}
i = 0i32;
while i < private_keys_len {
rpgp_skey_drop(*private_keys.offset(i as isize));
rpgp::rpgp_skey_drop(*private_keys.offset(i as isize));
i += 1
}
i = 0i32;
while i < public_keys_len {
rpgp_pkey_drop(*public_keys.offset(i as isize));
rpgp::rpgp_pkey_drop(*public_keys.offset(i as isize));
i += 1
}
if !encrypted.is_null() {
rpgp_msg_drop(encrypted);
rpgp::rpgp_msg_drop(encrypted);
}
if !decrypted.is_null() {
rpgp_message_decrypt_result_drop(decrypted);
rpgp::rpgp_message_decrypt_result_drop(decrypted);
}
return success;
}
@@ -707,24 +697,27 @@ pub unsafe extern "C" fn dc_pgp_symm_encrypt(
mut 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;
let mut decrypted: *mut rpgp::Message = 0 as *mut rpgp::Message;
if !(context.is_null()
|| passphrase.is_null()
|| plain == 0 as *mut libc::c_void
|| plain_bytes == 0i32 as libc::c_ulong
|| ret_ctext_armored.is_null())
{
decrypted =
rpgp_encrypt_bytes_with_password(plain as *const uint8_t, plain_bytes, passphrase);
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_msg_to_armored_str(decrypted);
*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_msg_drop(decrypted);
rpgp::rpgp_msg_drop(decrypted);
}
return success;
}
@@ -737,28 +730,28 @@ pub unsafe extern "C" fn dc_pgp_symm_decrypt(
mut ret_plain_text: *mut *mut libc::c_void,
mut ret_plain_bytes: *mut size_t,
) -> libc::c_int {
let mut decrypted_bytes: *mut rpgp_cvec = 0 as *mut rpgp_cvec;
let mut decrypted_bytes: *mut rpgp::cvec = 0 as *mut rpgp::cvec;
let mut success: libc::c_int = 0i32;
let mut encrypted: *mut rpgp_message = 0 as *mut rpgp_message;
let mut decrypted: *mut rpgp_message = 0 as *mut rpgp_message;
encrypted = rpgp_msg_from_bytes(ctext as *const uint8_t, ctext_bytes);
let mut encrypted: *mut rpgp::Message = 0 as *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_msg_decrypt_with_password(encrypted, passphrase);
decrypted = rpgp::rpgp_msg_decrypt_with_password(encrypted, passphrase);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
decrypted_bytes = rpgp_msg_to_bytes(decrypted);
decrypted_bytes = rpgp::rpgp_msg_to_bytes(decrypted);
if !(0 != dc_pgp_handle_rpgp_error(context)) {
*ret_plain_text = rpgp_cvec_data(decrypted_bytes) as *mut libc::c_void;
*ret_plain_bytes = rpgp_cvec_len(decrypted_bytes);
*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_msg_drop(encrypted);
rpgp::rpgp_msg_drop(encrypted);
}
if !decrypted.is_null() {
rpgp_msg_drop(decrypted);
rpgp::rpgp_msg_drop(decrypted);
}
return success;
}

View File

@@ -22,6 +22,7 @@ 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::*;
@@ -1740,8 +1741,10 @@ unsafe extern "C" fn create_adhoc_grp_id(
i += 1
}
/* make sha-256 from the string */
let mut binary_hash: *mut rpgp_cvec =
rpgp_hash_sha256(member_cs.buf as *const uint8_t, strlen(member_cs.buf));
let mut binary_hash: *mut crate::pgp::cvec = pgp::rpgp_hash_sha256(
member_cs.buf as *const uint8_t,
strlen(member_cs.buf) as usize,
);
if !binary_hash.is_null() {
ret = calloc(1i32 as libc::c_ulong, 256i32 as libc::c_ulong) as *mut libc::c_char;
if !ret.is_null() {
@@ -1750,11 +1753,11 @@ unsafe extern "C" 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,
*rpgp_cvec_data(binary_hash).offset(i as isize) as libc::c_int,
*pgp::rpgp_cvec_data(binary_hash).offset(i as isize) as libc::c_int,
);
i += 1
}
rpgp_cvec_drop(binary_hash);
pgp::rpgp_cvec_drop(binary_hash);
}
}
dc_array_free_ptr(member_addrs);

View File

@@ -19,8 +19,12 @@
ptr_wrapping_offset_from
)]
pub mod types;
pub mod x;
#[macro_use]
extern crate failure;
mod pgp;
mod types;
mod x;
pub mod dc_aheader;
pub mod dc_apeerstate;

90
src/pgp/c_vec.rs Normal file
View File

@@ -0,0 +1,90 @@
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<cvec> for Vec<u8> {
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<Vec<u8>> for cvec {
fn into(self) -> Vec<u8> {
unsafe { Vec::from_raw_parts(self.data, self.len, self.len) }
}
}
/// Get the length of the data of the given [cvec].
#[no_mangle]
pub unsafe extern "C" 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].
#[no_mangle]
pub unsafe extern "C" 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].
#[no_mangle]
pub unsafe extern "C" 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<u8> = b.into();
assert_eq!(a, c);
}
}
}

66
src/pgp/errors.rs Normal file
View File

@@ -0,0 +1,66 @@
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<Option<Box<Error>>> = 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<Box<Error>> {
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.
#[no_mangle]
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.
#[no_mangle]
pub unsafe extern "C" 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()
}

19
src/pgp/hash.rs Normal file
View File

@@ -0,0 +1,19 @@
use sha2::{Digest, Sha256};
use std::slice;
use crate::pgp::cvec;
/// Calculate the SHA256 hash of the given bytes.
#[no_mangle]
pub unsafe extern "C" 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()))
}

151
src/pgp/key.rs Normal file
View File

@@ -0,0 +1,151 @@
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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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"<hello@world.com>\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);
}
}
}

12
src/pgp/macros.rs Normal file
View File

@@ -0,0 +1,12 @@
#[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();
}
}
};
}

364
src/pgp/message.rs Normal file
View File

@@ -0,0 +1,364 @@
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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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::<Vec<_>>();
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::<Vec<_>>();
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].
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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()
}
}
#[no_mangle]
pub unsafe extern "C" 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::<Vec<_>>();
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))
}
#[no_mangle]
pub unsafe extern "C" 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::<Vec<_>>();
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))
}
#[no_mangle]
pub unsafe extern "C" 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))
}

25
src/pgp/mod.rs Normal file
View File

@@ -0,0 +1,25 @@
#[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.
#[no_mangle]
pub unsafe extern "C" fn rpgp_string_drop(p: *mut libc::c_char) {
let _ = std::ffi::CString::from_raw(p);
// Drop
}

68
src/pgp/public_key.rs Normal file
View File

@@ -0,0 +1,68 @@
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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
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].
#[no_mangle]
pub unsafe extern "C" 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].
#[no_mangle]
pub unsafe extern "C" fn rpgp_pkey_drop(pkey_ptr: *mut signed_public_key) {
assert!(!pkey_ptr.is_null());
let _pkey = &*pkey_ptr;
// Drop
}

207
src/pgp/secret_key.rs Normal file
View File

@@ -0,0 +1,207 @@
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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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.
#[no_mangle]
pub unsafe extern "C" 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<SignedSecretKey> {
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"<hello@world.com>\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);
}
}
}

View File

@@ -9,11 +9,6 @@ use crate::x::*;
extern "C" {
pub type __sFILEX;
pub type rpgp_Message;
pub type rpgp_PublicOrSecret;
pub type rpgp_SignedPublicKey;
pub type rpgp_SignedSecretKey;
pub type _telldir;
pub type mailstream_cancel;
pub type sqlite3;

View File

@@ -642,70 +642,6 @@ extern "C" {
pub fn dc_strbuilder_catf(_: *mut dc_strbuilder_t, format: *const libc::c_char, _: ...);
pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char;
// -- rpgp
pub fn rpgp_create_rsa_skey(
bits: uint32_t,
user_id: *const libc::c_char,
) -> *mut rpgp_signed_secret_key;
pub fn rpgp_cvec_data(cvec_ptr: *mut rpgp_cvec) -> *const uint8_t;
pub fn rpgp_cvec_drop(cvec_ptr: *mut rpgp_cvec);
pub fn rpgp_cvec_len(cvec_ptr: *mut rpgp_cvec) -> size_t;
pub fn rpgp_encrypt_bytes_to_keys(
bytes_ptr: *const uint8_t,
bytes_len: size_t,
pkeys_ptr: *const *const rpgp_signed_public_key,
pkeys_len: size_t,
) -> *mut rpgp_message;
pub fn rpgp_encrypt_bytes_with_password(
bytes_ptr: *const uint8_t,
bytes_len: size_t,
password_ptr: *const libc::c_char,
) -> *mut rpgp_message;
pub fn rpgp_key_drop(key_ptr: *mut rpgp_public_or_secret_key);
pub fn rpgp_key_fingerprint(key_ptr: *mut rpgp_public_or_secret_key) -> *mut rpgp_cvec;
pub fn rpgp_key_from_bytes(raw: *const uint8_t, len: size_t) -> *mut rpgp_public_or_secret_key;
pub fn rpgp_key_is_public(key_ptr: *mut rpgp_public_or_secret_key) -> bool;
pub fn rpgp_key_is_secret(key_ptr: *mut rpgp_public_or_secret_key) -> bool;
pub fn rpgp_last_error_length() -> libc::c_int;
pub fn rpgp_last_error_message() -> *mut libc::c_char;
pub fn rpgp_message_decrypt_result_drop(res_ptr: *mut rpgp_message_decrypt_result);
pub fn rpgp_msg_decrypt_no_pw(
msg_ptr: *const rpgp_message,
skeys_ptr: *const *const rpgp_signed_secret_key,
skeys_len: size_t,
pkeys_ptr: *const *const rpgp_signed_public_key,
pkeys_len: size_t,
) -> *mut rpgp_message_decrypt_result;
pub fn rpgp_msg_decrypt_with_password(
msg_ptr: *const rpgp_message,
password_ptr: *const libc::c_char,
) -> *mut rpgp_message;
pub fn rpgp_msg_drop(msg_ptr: *mut rpgp_message);
pub fn rpgp_msg_from_armor(msg_ptr: *const uint8_t, msg_len: size_t) -> *mut rpgp_message;
pub fn rpgp_msg_from_bytes(msg_ptr: *const uint8_t, msg_len: size_t) -> *mut rpgp_message;
pub fn rpgp_msg_to_armored(msg_ptr: *const rpgp_message) -> *mut rpgp_cvec;
pub fn rpgp_msg_to_armored_str(msg_ptr: *const rpgp_message) -> *mut libc::c_char;
pub fn rpgp_msg_to_bytes(msg_ptr: *const rpgp_message) -> *mut rpgp_cvec;
pub fn rpgp_pkey_drop(pkey_ptr: *mut rpgp_signed_public_key);
pub fn rpgp_pkey_from_bytes(raw: *const uint8_t, len: size_t) -> *mut rpgp_signed_public_key;
pub fn rpgp_pkey_to_bytes(pkey_ptr: *mut rpgp_signed_public_key) -> *mut rpgp_cvec;
pub fn rpgp_sign_encrypt_bytes_to_keys(
bytes_ptr: *const uint8_t,
bytes_len: size_t,
pkeys_ptr: *const *const rpgp_signed_public_key,
pkeys_len: size_t,
skey_ptr: *const rpgp_signed_secret_key,
) -> *mut rpgp_message;
pub fn rpgp_skey_drop(skey_ptr: *mut rpgp_signed_secret_key);
pub fn rpgp_skey_from_bytes(raw: *const uint8_t, len: size_t) -> *mut rpgp_signed_secret_key;
pub fn rpgp_skey_public_key(
skey_ptr: *mut rpgp_signed_secret_key,
) -> *mut rpgp_signed_public_key;
pub fn rpgp_skey_to_bytes(skey_ptr: *mut rpgp_signed_secret_key) -> *mut rpgp_cvec;
pub fn rpgp_string_drop(p: *mut libc::c_char);
pub fn rpgp_hash_sha256(bytes_ptr: *const uint8_t, bytes_len: size_t) -> *mut rpgp_cvec;
// -- Sqlite3
pub fn sqlite3_bind_blob(