use dcbor::prelude::*;
#[cfg(feature = "ssh-agent")]
use super::SSHAgentParams;
use super::{
Argon2idParams, HKDFParams, KeyDerivation, KeyDerivationMethod,
PBKDF2Params, ScryptParams,
};
use crate::{EncryptedMessage, Result, SymmetricKey};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum KeyDerivationParams {
HKDF(HKDFParams),
PBKDF2(PBKDF2Params),
Scrypt(ScryptParams),
Argon2id(Argon2idParams),
#[cfg(feature = "ssh-agent")]
SSHAgent(SSHAgentParams),
}
impl KeyDerivationParams {
pub fn method(&self) -> KeyDerivationMethod {
match self {
KeyDerivationParams::HKDF(_) => KeyDerivationMethod::HKDF,
KeyDerivationParams::PBKDF2(_) => KeyDerivationMethod::PBKDF2,
KeyDerivationParams::Scrypt(_) => KeyDerivationMethod::Scrypt,
KeyDerivationParams::Argon2id(_) => KeyDerivationMethod::Argon2id,
#[cfg(feature = "ssh-agent")]
KeyDerivationParams::SSHAgent(_) => KeyDerivationMethod::SSHAgent,
}
}
pub fn is_password_based(&self) -> bool {
matches!(
self,
KeyDerivationParams::PBKDF2(_)
| KeyDerivationParams::Scrypt(_)
| KeyDerivationParams::Argon2id(_)
)
}
pub fn is_ssh_agent(&self) -> bool {
#[cfg(feature = "ssh-agent")]
{
matches!(self, KeyDerivationParams::SSHAgent(_))
}
#[cfg(not(feature = "ssh-agent"))]
{
false
}
}
pub fn lock(
&mut self,
content_key: &SymmetricKey,
secret: impl AsRef<[u8]>,
) -> Result<EncryptedMessage> {
match self {
KeyDerivationParams::HKDF(params) => {
params.lock(content_key, secret)
}
KeyDerivationParams::PBKDF2(params) => {
params.lock(content_key, secret)
}
KeyDerivationParams::Scrypt(params) => {
params.lock(content_key, secret)
}
KeyDerivationParams::Argon2id(params) => {
params.lock(content_key, secret)
}
#[cfg(feature = "ssh-agent")]
KeyDerivationParams::SSHAgent(params) => {
params.lock(content_key, secret)
}
}
}
}
impl std::fmt::Display for KeyDerivationParams {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
KeyDerivationParams::HKDF(params) => write!(f, "{}", params),
KeyDerivationParams::PBKDF2(params) => write!(f, "{}", params),
KeyDerivationParams::Scrypt(params) => write!(f, "{}", params),
KeyDerivationParams::Argon2id(params) => write!(f, "{}", params),
#[cfg(feature = "ssh-agent")]
KeyDerivationParams::SSHAgent(params) => write!(f, "{}", params),
}
}
}
impl From<KeyDerivationParams> for CBOR {
fn from(value: KeyDerivationParams) -> Self {
match value {
KeyDerivationParams::HKDF(params) => params.into(),
KeyDerivationParams::PBKDF2(params) => params.into(),
KeyDerivationParams::Scrypt(params) => params.into(),
KeyDerivationParams::Argon2id(params) => params.into(),
#[cfg(feature = "ssh-agent")]
KeyDerivationParams::SSHAgent(params) => params.into(),
}
}
}
impl TryFrom<CBOR> for KeyDerivationParams {
type Error = dcbor::Error;
fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
let a = cbor.clone().try_into_array()?;
let mut iter = a.into_iter();
let index: usize = iter
.next()
.ok_or_else(|| dcbor::Error::msg("Missing index"))?
.try_into()?;
match KeyDerivationMethod::from_index(index) {
Some(KeyDerivationMethod::HKDF) => {
Ok(KeyDerivationParams::HKDF(HKDFParams::try_from(cbor)?))
}
Some(KeyDerivationMethod::PBKDF2) => {
Ok(KeyDerivationParams::PBKDF2(PBKDF2Params::try_from(cbor)?))
}
Some(KeyDerivationMethod::Scrypt) => {
Ok(KeyDerivationParams::Scrypt(ScryptParams::try_from(cbor)?))
}
Some(KeyDerivationMethod::Argon2id) => Ok(
KeyDerivationParams::Argon2id(Argon2idParams::try_from(cbor)?),
),
#[cfg(feature = "ssh-agent")]
Some(KeyDerivationMethod::SSHAgent) => Ok(
KeyDerivationParams::SSHAgent(SSHAgentParams::try_from(cbor)?),
),
None => Err(dcbor::Error::msg("Invalid KeyDerivationMethod")),
}
}
}