httpsig/crypto/
symmetric.rs1use super::AlgorithmName;
2use crate::{
3 error::{HttpSigError, HttpSigResult},
4 trace::*,
5};
6use base64::{engine::general_purpose, Engine as _};
7use hmac::{Hmac, Mac};
8use sha2::{Digest, Sha256};
9
10type HmacSha256 = Hmac<sha2::Sha256>;
11
12#[derive(Debug, Clone)]
14pub enum SharedKey {
17 HmacSha256(Vec<u8>),
19}
20
21impl SharedKey {
22 pub fn from_base64(key: &str) -> HttpSigResult<Self> {
24 debug!("Create SharedKey from base64 string");
25 let key = general_purpose::STANDARD.decode(key)?;
26 Ok(SharedKey::HmacSha256(key))
27 }
28}
29
30impl super::SigningKey for SharedKey {
31 fn sign(&self, data: &[u8]) -> HttpSigResult<Vec<u8>> {
33 match self {
34 SharedKey::HmacSha256(key) => {
35 debug!("Sign HmacSha256");
36 let mut mac = HmacSha256::new_from_slice(key).unwrap();
37 mac.update(data);
38 Ok(mac.finalize().into_bytes().to_vec())
39 }
40 }
41 }
42 fn key_id(&self) -> String {
44 use super::VerifyingKey;
45 <Self as VerifyingKey>::key_id(self)
46 }
47 fn alg(&self) -> AlgorithmName {
49 use super::VerifyingKey;
50 <Self as VerifyingKey>::alg(self)
51 }
52}
53impl super::VerifyingKey for SharedKey {
54 fn verify(&self, data: &[u8], expected_mac: &[u8]) -> HttpSigResult<()> {
56 use super::SigningKey;
57 debug!("Verify HmacSha256");
58 let calcurated_mac = self.sign(data)?;
59 if calcurated_mac == expected_mac {
60 Ok(())
61 } else {
62 Err(HttpSigError::InvalidSignature("Invalid MAC".to_string()))
63 }
64 }
65
66 fn key_id(&self) -> String {
68 match self {
69 SharedKey::HmacSha256(key) => {
70 let mut hasher = <Sha256 as Digest>::new();
71 hasher.update(key);
72 let hash = hasher.finalize();
73 general_purpose::STANDARD.encode(hash)
74 }
75 }
76 }
77 fn alg(&self) -> AlgorithmName {
79 match self {
80 SharedKey::HmacSha256(_) => AlgorithmName::HmacSha256,
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn symmetric_key_works() {
91 use super::super::{SigningKey, VerifyingKey};
92 let inner = b"01234567890123456789012345678901";
93 let key = SharedKey::HmacSha256(inner.to_vec());
94 let data = b"hello";
95 let signature = key.sign(data).unwrap();
96 let res = key.verify(data, &signature);
97 assert!(res.is_ok());
98 }
99}