use super::AlgorithmName;
use anyhow::Result;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
type HmacSha256 = Hmac<sha2::Sha256>;
pub enum SharedKey {
HmacSha256(Vec<u8>),
}
impl super::SigningKey for SharedKey {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
match self {
SharedKey::HmacSha256(key) => {
let mut mac = HmacSha256::new_from_slice(key).unwrap();
mac.update(data);
Ok(mac.finalize().into_bytes().to_vec())
}
}
}
fn key_id(&self) -> String {
use super::VerifyingKey;
<Self as VerifyingKey>::key_id(self)
}
fn alg(&self) -> AlgorithmName {
use super::VerifyingKey;
<Self as VerifyingKey>::alg(self)
}
}
impl super::VerifyingKey for SharedKey {
fn verify(&self, data: &[u8], expected_mac: &[u8]) -> Result<()> {
use super::SigningKey;
let calcurated_mac = self.sign(data)?;
if calcurated_mac == expected_mac {
Ok(())
} else {
Err(anyhow::anyhow!("Invalid mac"))
}
}
fn key_id(&self) -> String {
use base64::{engine::general_purpose, Engine as _};
match self {
SharedKey::HmacSha256(key) => {
let mut hasher = <Sha256 as Digest>::new();
hasher.update(key);
let hash = hasher.finalize();
general_purpose::URL_SAFE_NO_PAD.encode(hash)
}
}
}
fn alg(&self) -> AlgorithmName {
match self {
SharedKey::HmacSha256(_) => AlgorithmName::HmacSha256,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn symmetric_key_works() {
use super::super::{SigningKey, VerifyingKey};
let inner = b"01234567890123456789012345678901";
let key = SharedKey::HmacSha256(inner.to_vec());
let data = b"hello";
let signature = key.sign(data).unwrap();
key.verify(data, &signature).unwrap();
}
}