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 match self {
57 SharedKey::HmacSha256(key) => {
58 debug!("Verify HmacSha256");
59 let mut mac = HmacSha256::new_from_slice(key).unwrap();
60 mac.update(data);
61 mac.verify_slice(expected_mac)
62 .map_err(|_| HttpSigError::InvalidSignature("Invalid MAC".to_string()))
63 }
64 }
65 }
66
67 fn key_id(&self) -> String {
69 match self {
70 SharedKey::HmacSha256(key) => {
71 let mut hasher = <Sha256 as Digest>::new();
72 hasher.update(key);
73 let hash = hasher.finalize();
74 general_purpose::STANDARD.encode(hash)
75 }
76 }
77 }
78 fn alg(&self) -> AlgorithmName {
80 match self {
81 SharedKey::HmacSha256(_) => AlgorithmName::HmacSha256,
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn symmetric_key_works() {
92 use super::super::{SigningKey, VerifyingKey};
93 let inner = b"01234567890123456789012345678901";
94 let key = SharedKey::HmacSha256(inner.to_vec());
95 let data = b"hello";
96 let signature = key.sign(data).unwrap();
97 let res = key.verify(data, &signature);
98 assert!(res.is_ok());
99 }
100}