use std::ops::Deref;
use aws_lc_rs::{digest, hmac};
use base64::{Engine, prelude::BASE64_STANDARD};
use md5::{Digest, Md5};
use super::message::attributes::PasswordAlgorithm;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Password {
Md5([u8; 16]),
Sha256([u8; 32]),
}
impl Deref for Password {
type Target = [u8];
fn deref(&self) -> &Self::Target {
match self {
Password::Md5(it) => it,
Password::Sha256(it) => it,
}
}
}
pub fn hmac_sha1(key: &[u8], source: &[&[u8]]) -> [u8; 20] {
let key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, key);
let mut ctx = hmac::Context::with_key(&key);
for buf in source {
ctx.update(buf);
}
let mut result = [0u8; 20];
result.copy_from_slice(ctx.sign().as_ref());
result
}
pub fn fingerprint(bytes: &[u8]) -> u32 {
crc32fast::hash(bytes) ^ 0x5354_554e
}
pub fn generate_password(
username: &str,
password: &str,
realm: &str,
algorithm: PasswordAlgorithm,
) -> Password {
match algorithm {
PasswordAlgorithm::Md5 => {
let mut hasher = Md5::new();
hasher.update([username, realm, password].join(":"));
Password::Md5(hasher.finalize().into())
}
PasswordAlgorithm::Sha256 => {
let mut ctx = digest::Context::new(&digest::SHA256);
ctx.update([username, realm, password].join(":").as_bytes());
let mut result = [0u8; 32];
result.copy_from_slice(ctx.finish().as_ref());
Password::Sha256(result)
}
}
}
pub fn static_auth_secret(
username: &str,
secret: &str,
realm: &str,
algorithm: PasswordAlgorithm,
) -> Password {
let password =
BASE64_STANDARD.encode(hmac_sha1(secret.as_bytes(), &[username.as_bytes()]).as_slice());
generate_password(username, &password, realm, algorithm)
}