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(alg: &AlgorithmName, key: &str) -> HttpSigResult<Self> {
24 debug!("Create SharedKey from base64 string");
25 let key = general_purpose::STANDARD.decode(key)?;
26 match alg {
27 AlgorithmName::HmacSha256 => Ok(SharedKey::HmacSha256(key)),
28 _ => Err(HttpSigError::InvalidAlgorithmName(format!(
29 "Unsupported algorithm for SharedKey: {}",
30 alg
31 ))),
32 }
33 }
34}
35
36impl super::SigningKey for SharedKey {
37 fn sign(&self, data: &[u8]) -> HttpSigResult<Vec<u8>> {
39 match self {
40 SharedKey::HmacSha256(key) => {
41 debug!("Sign HmacSha256");
42 let mut mac = HmacSha256::new_from_slice(key).unwrap();
43 mac.update(data);
44 Ok(mac.finalize().into_bytes().to_vec())
45 }
46 }
47 }
48 fn key_id(&self) -> String {
50 use super::VerifyingKey;
51 <Self as VerifyingKey>::key_id(self)
52 }
53 fn alg(&self) -> AlgorithmName {
55 use super::VerifyingKey;
56 <Self as VerifyingKey>::alg(self)
57 }
58}
59impl super::VerifyingKey for SharedKey {
60 fn verify(&self, data: &[u8], expected_mac: &[u8]) -> HttpSigResult<()> {
62 match self {
63 SharedKey::HmacSha256(key) => {
64 debug!("Verify HmacSha256");
65 let mut mac = HmacSha256::new_from_slice(key).unwrap();
66 mac.update(data);
67 mac
68 .verify_slice(expected_mac)
69 .map_err(|_| HttpSigError::InvalidSignature("Invalid MAC".to_string()))
70 }
71 }
72 }
73
74 fn key_id(&self) -> String {
76 match self {
77 SharedKey::HmacSha256(key) => {
78 let mut hasher = <Sha256 as Digest>::new();
79 hasher.update(key);
80 let hash = hasher.finalize();
81 general_purpose::STANDARD.encode(hash)
82 }
83 }
84 }
85 fn alg(&self) -> AlgorithmName {
87 match self {
88 SharedKey::HmacSha256(_) => AlgorithmName::HmacSha256,
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn symmetric_key_works() {
99 use super::super::{SigningKey, VerifyingKey};
100 let inner = b"01234567890123456789012345678901";
101 let key = SharedKey::HmacSha256(inner.to_vec());
102 let data = b"hello";
103 let signature = key.sign(data).unwrap();
104 let res = key.verify(data, &signature);
105 assert!(res.is_ok());
106 }
107}