use crypto_core::CryptoError;
#[cfg(feature = "hkdf")]
use crypto_core::HkdfFailureKind;
#[cfg(any(
feature = "argon2id",
feature = "pbkdf2",
feature = "kmac",
feature = "concat-kdf"
))]
use crypto_core::KdfFailureKind;
use super::{BackendErrorReason, OperationError, PrimitiveErrorReason, ProviderErrorReason};
use crate::secret_material::{bind_operation_policy, SecretMaterialOperation};
#[cfg(feature = "argon2id")]
pub fn derive_argon2id(
request: &crypto_argon2id::DeriveKeyRequest<'_>,
) -> Result<crypto_argon2id::Argon2idDerivedKey, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_argon2id::derive_key(request).map_err(map_kdf_error)
}
#[cfg(feature = "argon2id")]
pub fn derive_argon2id_for_version(
kdf_version: u32,
secret: &[u8],
salt: &[u8],
) -> Result<crypto_argon2id::Argon2idDerivedKey, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_argon2id::derive_key_for_version(kdf_version, secret, salt).map_err(map_kdf_error)
}
#[cfg(feature = "hkdf")]
pub fn derive_hkdf<const N: usize>(
request: &crypto_hkdf::DeriveRequest<'_>,
) -> Result<crypto_hkdf::HkdfOutput<N>, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_hkdf::derive::<N>(request).map_err(map_hkdf_error)
}
#[cfg(feature = "hkdf")]
pub fn extract_hkdf_sha384(
salt: Option<&crypto_hkdf::HkdfSalt>,
ikm: &crypto_hkdf::HkdfInputKeyMaterial,
) -> Result<crypto_hkdf::HkdfSha384Prk, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_hkdf::extract_sha384(salt, ikm).map_err(map_hkdf_error)
}
#[cfg(feature = "hkdf")]
pub fn expand_hkdf_sha384<const N: usize>(
prk: &crypto_hkdf::HkdfSha384Prk,
info: &crypto_hkdf::HkdfInfo,
) -> Result<crypto_hkdf::HkdfOutput<N>, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_hkdf::expand_sha384::<N>(prk, info).map_err(map_hkdf_error)
}
#[cfg(feature = "hkdf")]
pub fn derive_domain_hkdf_key_32(
ikm: &crypto_hkdf::HkdfInputKeyMaterial,
salt: Option<&crypto_hkdf::HkdfSalt>,
purpose: crypto_hkdf::DomainKeyPurpose,
domain_tag: &crypto_hkdf::DomainTag,
) -> Result<crypto_hkdf::HkdfOutput<32>, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_hkdf::derive_domain_key_32(ikm, salt, purpose, domain_tag).map_err(map_hkdf_error)
}
#[cfg(feature = "pbkdf2")]
pub fn derive_pbkdf2(
request: &crypto_pbkdf2::Pbkdf2Request<'_>,
) -> Result<crypto_pbkdf2::Pbkdf2Output, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
if !(crypto_pbkdf2::PBKDF2_MODERN_MIN_ITERATIONS..=crypto_pbkdf2::PBKDF2_MAX_ITERATIONS)
.contains(&request.iterations.as_u32())
{
return Err(primitive(PrimitiveErrorReason::InvalidParameter));
}
crypto_pbkdf2::derive_key(request).map_err(map_kdf_error)
}
#[cfg(feature = "pbkdf2")]
pub fn derive_pbkdf2_from_raw(
prf: crypto_pbkdf2::Pbkdf2Prf,
password: &[u8],
salt: &[u8],
iterations: u32,
output_len: usize,
) -> Result<crypto_pbkdf2::Pbkdf2Output, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
let password =
crypto_pbkdf2::Pbkdf2Password::from_slice(password, prf).map_err(map_kdf_error)?;
let salt = crypto_pbkdf2::Pbkdf2Salt::from_slice(salt, prf).map_err(map_kdf_error)?;
let iterations =
crypto_pbkdf2::Pbkdf2Iterations::from_u32_modern(iterations, prf).map_err(map_kdf_error)?;
derive_pbkdf2(&crypto_pbkdf2::Pbkdf2Request {
prf,
password: &password,
salt: &salt,
iterations,
output_len,
})
}
#[cfg(feature = "kmac")]
pub fn derive_kmac256(
key: &crypto_kmac::Kmac256Key,
context: &[u8],
customization: &[u8],
output_len: usize,
) -> Result<crypto_kmac::Kmac256Output, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_kmac::derive_kmac256(key, context, customization, output_len).map_err(map_kdf_error)
}
#[cfg(feature = "concat-kdf")]
pub fn derive_jwa_concat_kdf_sha256<const N: usize>(
request: &crypto_concat_kdf::JwaConcatKdfRequest<'_>,
) -> Result<crypto_concat_kdf::JwaConcatKdfOutput<N>, OperationError> {
let _policy = bind_operation_policy(SecretMaterialOperation::KeyDerivation);
crypto_concat_kdf::derive_jwa_concat_kdf_sha256::<N>(request).map_err(map_kdf_error)
}
#[cfg(any(
feature = "argon2id",
feature = "pbkdf2",
feature = "kmac",
feature = "concat-kdf"
))]
fn map_kdf_error(error: CryptoError) -> OperationError {
match error {
CryptoError::Kdf {
kind: KdfFailureKind::InvalidSecretLength,
..
} => primitive(PrimitiveErrorReason::InvalidKey),
CryptoError::Kdf {
kind: KdfFailureKind::InvalidSaltLength | KdfFailureKind::InvalidOutputLength,
..
} => primitive(PrimitiveErrorReason::InvalidLength),
CryptoError::Kdf {
kind: KdfFailureKind::InvalidIterationCount | KdfFailureKind::InvalidParams,
..
} => primitive(PrimitiveErrorReason::InvalidParameter),
CryptoError::Kdf {
kind: KdfFailureKind::DerivationFailed,
..
} => backend(BackendErrorReason::Internal),
CryptoError::Unsupported => provider(ProviderErrorReason::UnsupportedAlgorithm),
_ => backend(BackendErrorReason::Internal),
}
}
#[cfg(feature = "hkdf")]
fn map_hkdf_error(error: CryptoError) -> OperationError {
match error {
CryptoError::Hkdf {
kind: HkdfFailureKind::InvalidIkmLength,
..
} => primitive(PrimitiveErrorReason::InvalidKey),
CryptoError::Hkdf {
kind:
HkdfFailureKind::InvalidDomainTagLength
| HkdfFailureKind::InvalidDomainTagByte
| HkdfFailureKind::InvalidOutputLength,
..
} => primitive(PrimitiveErrorReason::InvalidLength),
CryptoError::Hkdf {
kind: HkdfFailureKind::LengthOverflow,
..
} => primitive(PrimitiveErrorReason::LengthOverflow),
CryptoError::Hkdf {
kind: HkdfFailureKind::ExpandFailed,
..
} => backend(BackendErrorReason::Internal),
CryptoError::Unsupported => provider(ProviderErrorReason::UnsupportedAlgorithm),
_ => backend(BackendErrorReason::Internal),
}
}
fn primitive(reason: PrimitiveErrorReason) -> OperationError {
OperationError::Primitive { reason }
}
fn provider(reason: ProviderErrorReason) -> OperationError {
OperationError::Provider { reason }
}
fn backend(reason: BackendErrorReason) -> OperationError {
OperationError::Backend { reason }
}