summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi/src/packet/skesk.rs
blob: cf4ba2973e99728ce273122bff2a9c46046377ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//! Symmetrically encrypted session keys.

use std::slice;
use libc::size_t;

extern crate sequoia_openpgp as openpgp;
use super::Packet;

use crate::error::Status;
use crate::RefRaw;

/// Returns the session key.
///
/// `key` of size `key_len` must be a buffer large enough to hold the
/// session key.  If `key` is NULL, or not large enough, then the key
/// is not written to it.  Either way, `key_len` is set to the size of
/// the session key.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
pub extern "C" fn pgp_skesk_decrypt(errp: Option<&mut *mut crate::error::Error>,
                                        skesk: *const Packet,
                                        password: *const u8,
                                        password_len: size_t,
                                        algo: *mut u8, // XXX
                                        key: *mut u8,
                                        key_len: *mut size_t)
                                        -> Status {
    ffi_make_fry_from_errp!(errp);
    assert!(!password.is_null());
    let password = unsafe {
        slice::from_raw_parts(password, password_len as usize)
    };
    let algo = ffi_param_ref_mut!(algo);
    let key_len = ffi_param_ref_mut!(key_len);

    if let &openpgp::Packet::SKESK(ref skesk) = skesk.ref_raw() {
        match skesk.decrypt(&password.to_owned().into()) {
            Ok((a, k)) => {
                *algo = a.into();
                if !key.is_null() && *key_len >= k.len() {
                    unsafe {
                        ::std::ptr::copy(k.as_ptr(),
                                         key,
                                         k.len());
                    }
                }
                *key_len = k.len();
                Status::Success
            },
            Err(e) => ffi_try_status!(Err::<(), anyhow::Error>(e)),
        }
    } else {
        panic!("Not a SKESK packet");
    }
}