use crate::CryptoError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum KdfAlgo {
HkdfSha256,
HkdfSha384,
HkdfSha512,
Pbkdf2Sha256,
Pbkdf2Sha512,
Argon2id,
Scrypt,
Balloon,
}
#[cfg(feature = "pure")]
struct Pbkdf2Sha256Adapter;
#[cfg(feature = "pure")]
impl oxicrypto_core::Kdf for Pbkdf2Sha256Adapter {
fn name(&self) -> &'static str {
"PBKDF2-SHA-256"
}
fn derive(
&self,
ikm: &[u8],
salt: &[u8],
_info: &[u8],
okm_out: &mut [u8],
) -> Result<(), CryptoError> {
oxicrypto_kdf::pbkdf2_sha256(ikm, salt, 600_000, okm_out)
}
}
#[cfg(feature = "pure")]
struct Pbkdf2Sha512Adapter;
#[cfg(feature = "pure")]
impl oxicrypto_core::Kdf for Pbkdf2Sha512Adapter {
fn name(&self) -> &'static str {
"PBKDF2-SHA-512"
}
fn derive(
&self,
ikm: &[u8],
salt: &[u8],
_info: &[u8],
okm_out: &mut [u8],
) -> Result<(), CryptoError> {
oxicrypto_kdf::pbkdf2_sha512(ikm, salt, 210_000, okm_out)
}
}
#[cfg(feature = "pure")]
struct Argon2idAdapter;
#[cfg(feature = "pure")]
impl oxicrypto_core::Kdf for Argon2idAdapter {
fn name(&self) -> &'static str {
"Argon2id"
}
fn derive(
&self,
ikm: &[u8],
salt: &[u8],
_info: &[u8],
okm_out: &mut [u8],
) -> Result<(), CryptoError> {
let params = oxicrypto_kdf::Argon2Params {
m_cost: 65_536,
t_cost: 3,
p_cost: 4,
};
oxicrypto_kdf::argon2id_derive(ikm, salt, params, okm_out)
}
}
#[cfg(feature = "pure")]
struct ScryptAdapter;
#[cfg(feature = "pure")]
impl oxicrypto_core::Kdf for ScryptAdapter {
fn name(&self) -> &'static str {
"scrypt"
}
fn derive(
&self,
ikm: &[u8],
salt: &[u8],
_info: &[u8],
okm_out: &mut [u8],
) -> Result<(), CryptoError> {
oxicrypto_kdf::scrypt_derive(ikm, salt, 17, 8, 1, okm_out)
}
}
#[cfg(feature = "pure")]
struct BalloonAdapter;
#[cfg(feature = "pure")]
impl oxicrypto_core::Kdf for BalloonAdapter {
fn name(&self) -> &'static str {
"Balloon-SHA256"
}
fn derive(
&self,
ikm: &[u8],
salt: &[u8],
info: &[u8],
okm_out: &mut [u8],
) -> Result<(), CryptoError> {
let p = oxicrypto_kdf::BalloonParams::interactive();
let mut prk = [0u8; 32];
oxicrypto_kdf::balloon_sha256(ikm, salt, p.space_cost, p.time_cost, &mut prk)?;
oxicrypto_kdf::hkdf_sha256_expand(&prk, info, okm_out)
}
}
#[cfg(feature = "pure")]
#[must_use]
pub fn kdf_impl(algo: KdfAlgo) -> oxicrypto_core::Box<dyn oxicrypto_core::Kdf + Send + Sync> {
match algo {
KdfAlgo::HkdfSha256 => oxicrypto_core::Box::new(oxicrypto_kdf::HkdfSha256),
KdfAlgo::HkdfSha384 => oxicrypto_core::Box::new(oxicrypto_kdf::HkdfSha384),
KdfAlgo::HkdfSha512 => oxicrypto_core::Box::new(oxicrypto_kdf::HkdfSha512),
KdfAlgo::Pbkdf2Sha256 => oxicrypto_core::Box::new(Pbkdf2Sha256Adapter),
KdfAlgo::Pbkdf2Sha512 => oxicrypto_core::Box::new(Pbkdf2Sha512Adapter),
KdfAlgo::Argon2id => oxicrypto_core::Box::new(Argon2idAdapter),
KdfAlgo::Scrypt => oxicrypto_core::Box::new(ScryptAdapter),
KdfAlgo::Balloon => oxicrypto_core::Box::new(BalloonAdapter),
}
}
impl core::fmt::Display for KdfAlgo {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
KdfAlgo::HkdfSha256 => "HKDF-SHA-256",
KdfAlgo::HkdfSha384 => "HKDF-SHA-384",
KdfAlgo::HkdfSha512 => "HKDF-SHA-512",
KdfAlgo::Pbkdf2Sha256 => "PBKDF2-SHA-256",
KdfAlgo::Pbkdf2Sha512 => "PBKDF2-SHA-512",
KdfAlgo::Argon2id => "Argon2id",
KdfAlgo::Scrypt => "scrypt",
KdfAlgo::Balloon => "Balloon-SHA256",
})
}
}
impl core::str::FromStr for KdfAlgo {
type Err = CryptoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"HKDF-SHA-256" | "hkdf-sha-256" | "HKDFSHA256" => Ok(KdfAlgo::HkdfSha256),
"HKDF-SHA-384" | "hkdf-sha-384" | "HKDFSHA384" => Ok(KdfAlgo::HkdfSha384),
"HKDF-SHA-512" | "hkdf-sha-512" | "HKDFSHA512" => Ok(KdfAlgo::HkdfSha512),
"PBKDF2-SHA-256" | "pbkdf2-sha-256" | "PBKDF2SHA256" => Ok(KdfAlgo::Pbkdf2Sha256),
"PBKDF2-SHA-512" | "pbkdf2-sha-512" | "PBKDF2SHA512" => Ok(KdfAlgo::Pbkdf2Sha512),
"Argon2id" | "argon2id" | "ARGON2ID" => Ok(KdfAlgo::Argon2id),
"scrypt" | "SCRYPT" => Ok(KdfAlgo::Scrypt),
"Balloon-SHA256" | "balloon-sha256" | "balloon" => Ok(KdfAlgo::Balloon),
_ => Err(CryptoError::UnsupportedAlgorithm),
}
}
}
impl TryFrom<&str> for KdfAlgo {
type Error = CryptoError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
s.parse()
}
}