use super::prf::Prf;
use super::Error;
use super::Salt;
use hmac::Hmac;
use pbkdf2::pbkdf2;
use scrypt::{scrypt, ScryptParams};
use sha2::{Sha256, Sha512};
use std::fmt;
use std::str::FromStr;
pub const PBKDF2_KDF_NAME: &str = "pbkdf2";
pub const SCRYPT_KDF_NAME: &str = "scrypt";
pub const DEFAULT_DK_LENGTH: usize = 32;
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
pub struct KdfParams {
#[serde(flatten)]
pub kdf: Kdf,
pub dklen: usize,
pub salt: Salt,
}
impl Default for KdfParams {
fn default() -> Self {
Self {
kdf: Kdf::default(),
dklen: DEFAULT_DK_LENGTH,
salt: Salt::default(),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum KdfDepthLevel {
Normal = 1024,
High = 8096,
Ultra = 262_144,
}
impl fmt::Display for KdfDepthLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let printable = match *self {
KdfDepthLevel::Normal => "normal",
KdfDepthLevel::High => "high",
KdfDepthLevel::Ultra => "ultra",
};
write!(f, "{}", printable)
}
}
impl FromStr for KdfDepthLevel {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"normal" => Ok(KdfDepthLevel::Normal),
"high" => Ok(KdfDepthLevel::High),
"ultra" => Ok(KdfDepthLevel::Ultra),
v => Err(Error::InvalidKdfDepth(v.to_string())),
}
}
}
impl Default for KdfDepthLevel {
fn default() -> Self {
KdfDepthLevel::Normal
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(untagged)]
pub enum Kdf {
#[serde(rename = "pbkdf2")]
Pbkdf2 {
prf: Prf,
c: u32,
},
#[serde(rename = "scrypt")]
Scrypt {
n: u32,
r: u32,
p: u32,
},
}
impl Kdf {
pub fn derive(&self, len: usize, kdf_salt: &[u8], passphrase: &str) -> Vec<u8> {
let mut key = vec![0u8; len];
match *self {
Kdf::Pbkdf2 { prf, c } => {
match prf {
Prf::HmacSha256 => {
let _hmac = prf.hmac(passphrase);
pbkdf2::<Hmac<Sha256>>(
passphrase.as_bytes(),
kdf_salt,
c as usize,
&mut key,
);
}
Prf::HmacSha512 => {
pbkdf2::<Hmac<Sha512>>(
passphrase.as_bytes(),
kdf_salt,
c as usize,
&mut key,
);
}
};
}
Kdf::Scrypt { n, r, p } => {
let log_n = (n as f64).log2().round() as u8;
let params = ScryptParams::new(log_n, r, p).expect("Invalid Scrypt parameters");
scrypt(passphrase.as_bytes(), kdf_salt, ¶ms, &mut key).expect("Scrypt failed");
}
}
key
}
}
impl Default for Kdf {
fn default() -> Self {
Kdf::Scrypt {
n: 1024,
r: 8,
p: 1,
}
}
}
impl From<KdfDepthLevel> for Kdf {
fn from(sec: KdfDepthLevel) -> Self {
Kdf::from((sec as u32, 8, 1))
}
}
impl From<u32> for Kdf {
fn from(c: u32) -> Self {
Kdf::Pbkdf2 {
prf: Prf::default(),
c,
}
}
}
impl From<(u32, u32, u32)> for Kdf {
fn from(t: (u32, u32, u32)) -> Self {
Kdf::Scrypt {
n: t.0,
r: t.1,
p: t.2,
}
}
}
impl FromStr for Kdf {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
_ if s == PBKDF2_KDF_NAME => Ok(Kdf::Pbkdf2 {
prf: Prf::default(),
c: 262_144,
}),
_ if s == SCRYPT_KDF_NAME => Ok(Kdf::default()),
_ => Err(Error::UnsupportedKdf(s.to_string())),
}
}
}
impl fmt::Display for Kdf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Kdf::Pbkdf2 { .. } => f.write_str(PBKDF2_KDF_NAME),
Kdf::Scrypt { .. } => f.write_str(SCRYPT_KDF_NAME),
}
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::tests::*;
#[test]
fn should_derive_key_via_pbkdf2() {
let kdf_salt =
to_32bytes("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd");
assert_eq!(
hex::encode(Kdf::from(8).derive(32, &kdf_salt, "testpassword")),
"031dc7e0f4f375f6d6fdab7ad8d71834d844e39a6b62f9fb98d942bab76db0f9"
);
}
#[test]
fn should_derive_key_via_scrypt() {
let kdf_salt =
to_32bytes("fd4acb81182a2c8fa959d180967b374277f2ccf2f7f401cb08d042cc785464b4");
assert_eq!(
hex::encode(Kdf::from((2, 8, 1)).derive(32, &kdf_salt, "1234567890")),
"52a5dacfcf80e5111d2c7fbed177113a1b48a882b066a017f2c856086680fac7"
);
}
#[test]
fn should_derive_test_vector_pbkdf() {
let kdf_salt =
to_32bytes("ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd");
assert_eq!(
hex::encode(Kdf::from(262144).derive(32, &kdf_salt, "testpassword")),
"f06d69cdc7da0faffb1008270bca38f5e31891a3a773950e6d0fea48a7188551"
);
}
}