use super::errors::{NoCryptoError, PrivateKeyError};
pub fn hmac_output_len(algorithm: &str) -> Option<usize> {
match algorithm {
"md5" => Some(16),
"sha1" => Some(20),
"sha224" => Some(28),
"sha256" => Some(32),
"sha384" => Some(48),
"sha512" => Some(64),
_ => None,
}
}
pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
a.iter()
.zip(b.iter())
.fold(0u8, |acc, (x, y)| acc | (x ^ y))
== 0
}
pub trait DataHasher {
type Error: std::error::Error + Send + Sync + 'static;
fn hash_data(&self, algorithm: &str, data: &[u8]) -> Result<Vec<u8>, Self::Error>;
}
pub trait HmacProvider {
type Error: std::error::Error + Send + Sync + 'static;
fn hmac_compute(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
) -> Result<Vec<u8>, Self::Error>;
fn hmac_verify(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
expected: &[u8],
) -> Result<(), Self::Error>;
fn constant_time_eq(&self, a: &[u8], b: &[u8]) -> bool {
constant_time_eq(a, b)
}
}
pub trait Pbkdf2Provider {
type Error: std::error::Error + Send + Sync + 'static;
fn pbkdf2_hmac(
&self,
algorithm: &str,
password: &[u8],
salt: &[u8],
iterations: usize,
length: usize,
) -> Result<Vec<u8>, Self::Error>;
}
pub trait BlockCipherProvider {
type Error: std::error::Error + Send + Sync + 'static;
fn aes_cbc_encrypt(
&self,
key: &[u8],
iv: &[u8],
plaintext: &[u8],
pad: bool,
) -> Result<Vec<u8>, Self::Error>;
fn aes_cbc_decrypt(
&self,
key: &[u8],
iv: &[u8],
ciphertext: &[u8],
unpad: bool,
) -> Result<Vec<u8>, Self::Error>;
fn des3_cbc_encrypt(
&self,
key: &[u8],
iv: &[u8],
plaintext: &[u8],
pad: bool,
) -> Result<Vec<u8>, Self::Error>;
fn des3_cbc_decrypt(
&self,
key: &[u8],
iv: &[u8],
ciphertext: &[u8],
unpad: bool,
) -> Result<Vec<u8>, Self::Error>;
fn aes_gcm_encrypt(
&self,
key: &[u8],
nonce: &[u8],
plaintext: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, Self::Error>;
fn aes_gcm_decrypt(
&self,
key: &[u8],
nonce: &[u8],
ciphertext_with_tag: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, Self::Error>;
}
pub trait SecureRandom {
type Error: std::error::Error + Send + Sync + 'static;
fn rand_bytes(&self, out: &mut [u8]) -> Result<(), Self::Error>;
}
pub trait HashState: Send {
fn update(&mut self, data: &[u8]);
fn finalize_boxed(self: Box<Self>) -> Vec<u8>;
}
pub trait StreamingHasher {
type Error: std::error::Error + Send + Sync + 'static;
fn new_hash(&self, algorithm: &str) -> Result<Box<dyn HashState>, Self::Error>;
}
pub trait ErasedStreamingHasher {
fn new_hash_erased(&self, algorithm: &str) -> Result<Box<dyn HashState>, PrivateKeyError>;
}
impl StreamingHasher for dyn ErasedStreamingHasher + '_ {
type Error = PrivateKeyError;
fn new_hash(&self, algorithm: &str) -> Result<Box<dyn HashState>, PrivateKeyError> {
self.new_hash_erased(algorithm)
}
}
impl StreamingHasher for Box<dyn ErasedStreamingHasher> {
type Error = PrivateKeyError;
fn new_hash(&self, algorithm: &str) -> Result<Box<dyn HashState>, PrivateKeyError> {
self.as_ref().new_hash_erased(algorithm)
}
}
pub trait ErasedDataHasher {
fn hash_data_erased(&self, algorithm: &str, data: &[u8]) -> Result<Vec<u8>, PrivateKeyError>;
}
impl DataHasher for dyn ErasedDataHasher + '_ {
type Error = PrivateKeyError;
fn hash_data(&self, algorithm: &str, data: &[u8]) -> Result<Vec<u8>, PrivateKeyError> {
self.hash_data_erased(algorithm, data)
}
}
impl DataHasher for Box<dyn ErasedDataHasher> {
type Error = PrivateKeyError;
fn hash_data(&self, algorithm: &str, data: &[u8]) -> Result<Vec<u8>, PrivateKeyError> {
self.as_ref().hash_data_erased(algorithm, data)
}
}
pub trait ErasedHmacProvider {
fn hmac_compute_erased(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
) -> Result<Vec<u8>, PrivateKeyError>;
fn hmac_verify_erased(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
expected: &[u8],
) -> Result<(), PrivateKeyError>;
}
impl HmacProvider for dyn ErasedHmacProvider + '_ {
type Error = PrivateKeyError;
fn hmac_compute(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
) -> Result<Vec<u8>, PrivateKeyError> {
self.hmac_compute_erased(algorithm, key, data)
}
fn hmac_verify(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
expected: &[u8],
) -> Result<(), PrivateKeyError> {
self.hmac_verify_erased(algorithm, key, data, expected)
}
}
impl HmacProvider for Box<dyn ErasedHmacProvider> {
type Error = PrivateKeyError;
fn hmac_compute(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
) -> Result<Vec<u8>, PrivateKeyError> {
self.as_ref().hmac_compute_erased(algorithm, key, data)
}
fn hmac_verify(
&self,
algorithm: &str,
key: &[u8],
data: &[u8],
expected: &[u8],
) -> Result<(), PrivateKeyError> {
self.as_ref()
.hmac_verify_erased(algorithm, key, data, expected)
}
}
pub struct NoSymmetricCrypto;
impl DataHasher for NoSymmetricCrypto {
type Error = NoCryptoError;
fn hash_data(&self, _: &str, _: &[u8]) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
}
impl HmacProvider for NoSymmetricCrypto {
type Error = NoCryptoError;
fn hmac_compute(&self, _: &str, _: &[u8], _: &[u8]) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
fn hmac_verify(&self, _: &str, _: &[u8], _: &[u8], _: &[u8]) -> Result<(), NoCryptoError> {
Err(NoCryptoError)
}
}
impl Pbkdf2Provider for NoSymmetricCrypto {
type Error = NoCryptoError;
fn pbkdf2_hmac(
&self,
_: &str,
_: &[u8],
_: &[u8],
_: usize,
_: usize,
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
}
impl BlockCipherProvider for NoSymmetricCrypto {
type Error = NoCryptoError;
fn aes_cbc_encrypt(
&self,
_: &[u8],
_: &[u8],
_: &[u8],
_: bool,
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
fn aes_cbc_decrypt(
&self,
_: &[u8],
_: &[u8],
_: &[u8],
_: bool,
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
fn des3_cbc_encrypt(
&self,
_: &[u8],
_: &[u8],
_: &[u8],
_: bool,
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
fn des3_cbc_decrypt(
&self,
_: &[u8],
_: &[u8],
_: &[u8],
_: bool,
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
fn aes_gcm_encrypt(
&self,
_: &[u8],
_: &[u8],
_: &[u8],
_: &[u8],
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
fn aes_gcm_decrypt(
&self,
_: &[u8],
_: &[u8],
_: &[u8],
_: &[u8],
) -> Result<Vec<u8>, NoCryptoError> {
Err(NoCryptoError)
}
}
impl SecureRandom for NoSymmetricCrypto {
type Error = NoCryptoError;
fn rand_bytes(&self, _: &mut [u8]) -> Result<(), NoCryptoError> {
Err(NoCryptoError)
}
}
impl ErasedDataHasher for NoSymmetricCrypto {
fn hash_data_erased(&self, _: &str, _: &[u8]) -> Result<Vec<u8>, PrivateKeyError> {
Err(PrivateKeyError::new(NoCryptoError))
}
}
impl ErasedStreamingHasher for NoSymmetricCrypto {
fn new_hash_erased(&self, _: &str) -> Result<Box<dyn HashState>, PrivateKeyError> {
Err(PrivateKeyError::new(NoCryptoError))
}
}
impl ErasedHmacProvider for NoSymmetricCrypto {
fn hmac_compute_erased(&self, _: &str, _: &[u8], _: &[u8]) -> Result<Vec<u8>, PrivateKeyError> {
Err(PrivateKeyError::new(NoCryptoError))
}
fn hmac_verify_erased(
&self,
_: &str,
_: &[u8],
_: &[u8],
_: &[u8],
) -> Result<(), PrivateKeyError> {
Err(PrivateKeyError::new(NoCryptoError))
}
}
impl ErasedStreamingHmacProvider for NoSymmetricCrypto {
fn new_hmac_erased(&self, _: &str, _: &[u8]) -> Result<Box<dyn HmacState>, PrivateKeyError> {
Err(PrivateKeyError::new(NoCryptoError))
}
}
pub trait HmacState: Send {
fn update(&mut self, data: &[u8]);
fn finalize_boxed(self: Box<Self>) -> Vec<u8>;
}
pub trait StreamingHmacProvider {
type Error: std::error::Error + Send + Sync + 'static;
fn new_hmac(&self, algorithm: &str, key: &[u8]) -> Result<Box<dyn HmacState>, Self::Error>;
}
pub trait ErasedStreamingHmacProvider {
fn new_hmac_erased(
&self,
algorithm: &str,
key: &[u8],
) -> Result<Box<dyn HmacState>, PrivateKeyError>;
}
impl StreamingHmacProvider for dyn ErasedStreamingHmacProvider + '_ {
type Error = PrivateKeyError;
fn new_hmac(&self, algorithm: &str, key: &[u8]) -> Result<Box<dyn HmacState>, PrivateKeyError> {
self.new_hmac_erased(algorithm, key)
}
}
impl StreamingHmacProvider for Box<dyn ErasedStreamingHmacProvider> {
type Error = PrivateKeyError;
fn new_hmac(&self, algorithm: &str, key: &[u8]) -> Result<Box<dyn HmacState>, PrivateKeyError> {
self.as_ref().new_hmac_erased(algorithm, key)
}
}
pub fn hkdf_extract<P>(
hmac: &P,
algorithm: &str,
salt: Option<&[u8]>,
ikm: &[u8],
) -> Result<Vec<u8>, P::Error>
where
P: HmacProvider,
{
let hash_len = hmac_output_len(algorithm).unwrap_or(32);
let default_salt: Vec<u8>;
let effective_salt = match salt {
Some(s) => s,
None => {
default_salt = vec![0u8; hash_len];
&default_salt
}
};
hmac.hmac_compute(algorithm, effective_salt, ikm)
}
pub fn hkdf_expand<P>(
hmac: &P,
algorithm: &str,
prk: &[u8],
info: &[u8],
length: usize,
) -> Result<Vec<u8>, P::Error>
where
P: HmacProvider,
{
if length == 0 {
return Ok(Vec::new());
}
let hash_len = hmac_output_len(algorithm).unwrap_or(32);
let n = length.div_ceil(hash_len);
debug_assert!(n <= 255, "hkdf_expand: length too large for algorithm");
let mut okm = Vec::with_capacity(length);
let mut t: Vec<u8> = Vec::new(); for i in 1u8..=(n as u8) {
let mut input = Vec::with_capacity(t.len() + info.len() + 1);
input.extend_from_slice(&t);
input.extend_from_slice(info);
input.push(i);
t = hmac.hmac_compute(algorithm, prk, &input)?;
okm.extend_from_slice(&t);
}
okm.truncate(length);
Ok(okm)
}