1use std::fmt::Debug;
2
3use hmac::{Hmac, Mac};
4use sha2::{Digest, Sha256, Sha512};
5
6pub trait HttpSignatureSign: Debug + Send + Sync + 'static {
9 fn http_sign(&self, bytes_to_sign: &[u8]) -> String;
13}
14
15pub trait HttpSignatureVerify: Debug + Send + Sync + 'static {
18 fn http_verify(&self, bytes_to_verify: &[u8], signature: &str) -> bool;
22}
23
24pub trait HttpDigest: Debug + Send + Sync + 'static {
28 fn name(&self) -> &str;
31 fn http_digest(&self, bytes_to_digest: &[u8]) -> String;
35}
36
37macro_rules! hmac_signature {
38 ($typename:ident($algorithm:ident) = $name:literal) => {
39 #[doc = "Implementation of the '"]
40 #[doc = $name]
41 #[doc = "' HTTP signature scheme."]
42 #[derive(Debug)]
43 pub struct $typename(Hmac<$algorithm>);
44
45 impl $typename {
46 pub fn new(key: &[u8]) -> Self {
49 Self(Hmac::new_from_slice(key).expect("Hmac construction should be infallible"))
50 }
51 }
52
53 impl HttpSignatureSign for $typename {
54 fn http_sign(&self, bytes_to_sign: &[u8]) -> String {
55 let mut hmac = self.0.clone();
56 hmac.update(bytes_to_sign);
57 let tag = hmac.finalize().into_bytes();
58 base64::encode(tag)
59 }
60 }
61 impl HttpSignatureVerify for $typename {
62 fn http_verify(&self, bytes_to_verify: &[u8], signature: &str) -> bool {
63 let tag = match base64::decode(signature) {
64 Ok(tag) => tag,
65 Err(_) => return false,
66 };
67 let mut hmac = self.0.clone();
68 hmac.update(bytes_to_verify);
69 hmac.verify_slice(&tag).is_ok()
70 }
71 }
72 };
73}
74
75hmac_signature!(HmacSha256(Sha256) = "hmac-sha256");
76hmac_signature!(HmacSha512(Sha512) = "hmac-sha512");
77
78impl HttpDigest for Sha256 {
79 fn name(&self) -> &str {
80 "SHA-256"
81 }
82 fn http_digest(&self, bytes_to_digest: &[u8]) -> String {
83 base64::encode(Self::digest(bytes_to_digest))
84 }
85}
86
87impl HttpDigest for Sha512 {
88 fn name(&self) -> &str {
89 "SHA-512"
90 }
91 fn http_digest(&self, bytes_to_digest: &[u8]) -> String {
92 base64::encode(Self::digest(bytes_to_digest))
93 }
94}
95
96#[cfg(feature = "openssl")]
97mod openssl;
98#[cfg(feature = "openssl")]
99pub use self::openssl::*;
100
101#[cfg(all(not(feature = "openssl"), feature = "ring"))]
102mod ring;
103#[cfg(all(not(feature = "openssl"), feature = "ring"))]
104pub use self::ring::*;