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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::ptr;

use ffi;
use libc::c_int;

use crate::{digest::Algorithm as DigestAlgorithm, error::return_err, Result};

ffi_enum_wrapper! {
    pub enum Algorithm: c_int {
        SimpleS2K = ffi::GCRY_KDF_SIMPLE_S2K,
        SaltedS2K = ffi::GCRY_KDF_SALTED_S2K,
        IteratedSaltedS2K = ffi::GCRY_KDF_ITERSALTED_S2K,
        Pbkdf1 = ffi::GCRY_KDF_PBKDF1,
        Pbkdf2 = ffi::GCRY_KDF_PBKDF2,
        Scrypt = ffi::GCRY_KDF_SCRYPT,
    }
}

#[inline]
pub fn derive(
    algo: Algorithm, subalgo: i32, iter: u32, secret: &[u8], salt: Option<&[u8]>, key: &mut [u8],
) -> Result<()> {
    let _ = crate::init_default();
    unsafe {
        let salt = salt.map_or((ptr::null(), 0), |s| (s.as_ptr(), s.len()));
        return_err!(ffi::gcry_kdf_derive(
            secret.as_ptr().cast(),
            secret.len(),
            algo.raw(),
            subalgo as c_int,
            salt.0.cast(),
            salt.1,
            iter.into(),
            key.len(),
            key.as_mut_ptr().cast(),
        ));
    }
    Ok(())
}

#[inline]
pub fn s2k_derive(
    digest: DigestAlgorithm, iter: u32, secret: &[u8], salt: Option<&[u8]>, key: &mut [u8],
) -> Result<()> {
    let variant = match (iter, salt.is_some()) {
        (0, true) => Algorithm::SaltedS2K,
        (_, true) => Algorithm::IteratedSaltedS2K,
        _ => Algorithm::SimpleS2K,
    };
    derive(variant, digest.raw(), iter, secret, salt, key)
}

#[inline]
pub fn pbkdf1_derive(
    digest: DigestAlgorithm, iter: u32, secret: &[u8], salt: &[u8], key: &mut [u8],
) -> Result<()> {
    derive(
        Algorithm::Pbkdf1,
        digest.raw(),
        iter,
        secret,
        Some(salt),
        key,
    )
}

#[inline]
pub fn pbkdf2_derive(
    digest: DigestAlgorithm, iter: u32, secret: &[u8], salt: &[u8], key: &mut [u8],
) -> Result<()> {
    derive(
        Algorithm::Pbkdf2,
        digest.raw(),
        iter,
        secret,
        Some(salt),
        key,
    )
}

#[inline]
pub fn scrypt_derive(n: u32, p: u32, secret: &[u8], salt: &[u8], key: &mut [u8]) -> Result<()> {
    derive(Algorithm::Scrypt, n as i32, p, secret, Some(salt), key)
}