use libsodium_sys::*;
use crate::{Result, error::anyhow};
#[derive(Debug, Clone, Copy)]
pub enum Limit {
Interactive,
Moderate,
Sensitive,
Custom(usize),
}
impl Limit {
pub fn eval(&self, limits: [usize; 3]) -> usize {
match self {
Self::Interactive => limits[0],
Self::Moderate => limits[1],
Self::Sensitive => limits[2],
Self::Custom(val) => *val,
}
}
}
pub struct Algorithm {
pub salt_len: usize,
pub ops_limits: [usize; 3],
pub mem_limits: [usize; 3],
derive_key: unsafe extern "C" fn(
out: *mut libc::c_uchar,
outlen: libc::c_ulonglong,
passwd: *const libc::c_char,
passwdlen: libc::c_ulonglong,
salt: *const libc::c_uchar,
opslimit: libc::c_ulonglong,
memlimit: usize,
alg: libc::c_int,
) -> libc::c_int,
}
impl Algorithm {
fn check(&self, salt: &[u8]) {
assert_eq!(self.salt_len, salt.len());
}
pub fn derive_key(
&self,
key: &mut [u8],
password: &[u8],
salt: &[u8],
ops_limit: Limit,
mem_limit: Limit,
) -> Result<()> {
self.check(salt);
unsafe {
if (self.derive_key)(
key.as_mut_ptr() as _,
key.len() as _,
password.as_ptr() as _,
password.len() as _,
salt.as_ptr() as _,
ops_limit.eval(self.ops_limits) as _,
mem_limit.eval(self.mem_limits) as _,
crypto_pwhash_ALG_ARGON2ID13 as _,
) == 0
{
Ok(())
} else {
Err(anyhow!(@CryptoError "failed to derive key from password"))
}
}
}
}
pub const ARGON2_ID13: Algorithm = Algorithm {
salt_len: crypto_pwhash_argon2id_SALTBYTES as _,
ops_limits: [
crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE as _,
crypto_pwhash_argon2id_OPSLIMIT_MODERATE as _,
crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE as _,
],
mem_limits: [
crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE as _,
crypto_pwhash_argon2id_MEMLIMIT_MODERATE as _,
crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE as _,
],
derive_key: crypto_pwhash_argon2id,
};