use std::fmt::Debug;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256, Sha512};
pub trait HttpSignatureSign: Debug + Send + Sync + 'static {
fn http_sign(&self, bytes_to_sign: &[u8]) -> String;
}
pub trait HttpSignatureVerify: Debug + Send + Sync + 'static {
fn http_verify(&self, bytes_to_verify: &[u8], signature: &str) -> bool;
}
pub trait HttpDigest: Debug + Send + Sync + 'static {
fn name(&self) -> &str;
fn http_digest(&self, bytes_to_digest: &[u8]) -> String;
}
macro_rules! hmac_signature {
($typename:ident($algorithm:ident) = $name:literal) => {
#[doc = "Implementation of the '"]
#[doc = $name]
#[doc = "' HTTP signature scheme."]
#[derive(Debug)]
pub struct $typename(Hmac<$algorithm>);
impl $typename {
pub fn new(key: &[u8]) -> Self {
Self(Hmac::new_from_slice(key).expect("Hmac construction should be infallible"))
}
}
impl HttpSignatureSign for $typename {
fn http_sign(&self, bytes_to_sign: &[u8]) -> String {
let mut hmac = self.0.clone();
hmac.update(bytes_to_sign);
let tag = hmac.finalize().into_bytes();
base64::encode(tag)
}
}
impl HttpSignatureVerify for $typename {
fn http_verify(&self, bytes_to_verify: &[u8], signature: &str) -> bool {
let tag = match base64::decode(signature) {
Ok(tag) => tag,
Err(_) => return false,
};
let mut hmac = self.0.clone();
hmac.update(bytes_to_verify);
hmac.verify_slice(&tag).is_ok()
}
}
};
}
hmac_signature!(HmacSha256(Sha256) = "hmac-sha256");
hmac_signature!(HmacSha512(Sha512) = "hmac-sha512");
impl HttpDigest for Sha256 {
fn name(&self) -> &str {
"SHA-256"
}
fn http_digest(&self, bytes_to_digest: &[u8]) -> String {
base64::encode(Self::digest(bytes_to_digest))
}
}
impl HttpDigest for Sha512 {
fn name(&self) -> &str {
"SHA-512"
}
fn http_digest(&self, bytes_to_digest: &[u8]) -> String {
base64::encode(Self::digest(bytes_to_digest))
}
}
#[cfg(feature = "openssl")]
mod openssl;
#[cfg(feature = "openssl")]
pub use self::openssl::*;
#[cfg(all(not(feature = "openssl"), feature = "ring"))]
mod ring;
#[cfg(all(not(feature = "openssl"), feature = "ring"))]
pub use self::ring::*;