1use crate::algorithm::Algorithm;
2use crate::error::{Error, Result};
3use crate::keys::Key;
4use crate::utils::base64url;
5
6use constant_time_eq::constant_time_eq;
7use hmac::{Hmac, Mac};
8use sha2::{Sha256, Sha384, Sha512};
9
10pub struct HS256;
12
13pub struct HS384;
15
16pub struct HS512;
18
19impl Algorithm for HS256 {
20 fn name(&self) -> &'static str {
21 "HS256"
22 }
23
24 fn verify(&self, signing_input: &str, signature: &str, key: &Key) -> Result<()> {
25 let symmetric_key = key.as_symmetric()?;
26 verify_hs256(signing_input, signature, symmetric_key.as_bytes())
27 }
28}
29
30impl Algorithm for HS384 {
31 fn name(&self) -> &'static str {
32 "HS384"
33 }
34
35 fn verify(&self, signing_input: &str, signature: &str, key: &Key) -> Result<()> {
36 let symmetric_key = key.as_symmetric()?;
37 verify_hs384(signing_input, signature, symmetric_key.as_bytes())
38 }
39}
40
41impl Algorithm for HS512 {
42 fn name(&self) -> &'static str {
43 "HS512"
44 }
45
46 fn verify(&self, signing_input: &str, signature: &str, key: &Key) -> Result<()> {
47 let symmetric_key = key.as_symmetric()?;
48 verify_hs512(signing_input, signature, symmetric_key.as_bytes())
49 }
50}
51
52fn verify_hs256(signing_input: &str, signature: &str, secret: &[u8]) -> Result<()> {
54 let provided_signature = base64url::decode_bytes(signature)?;
55
56 let mut mac = Hmac::<Sha256>::new_from_slice(secret).map_err(|_| Error::SignatureInvalid)?;
57 mac.update(signing_input.as_bytes());
58 let expected_signature = mac.finalize().into_bytes();
59
60 if provided_signature.len() != expected_signature.len() {
61 return Err(Error::SignatureInvalid);
62 }
63
64 if constant_time_eq(&provided_signature, &expected_signature) {
65 Ok(())
66 } else {
67 Err(Error::SignatureInvalid)
68 }
69}
70
71fn verify_hs384(signing_input: &str, signature: &str, secret: &[u8]) -> Result<()> {
73 let provided_signature = base64url::decode_bytes(signature)?;
74
75 let mut mac = Hmac::<Sha384>::new_from_slice(secret).map_err(|_| Error::SignatureInvalid)?;
76 mac.update(signing_input.as_bytes());
77 let expected_signature = mac.finalize().into_bytes();
78
79 if provided_signature.len() != expected_signature.len() {
80 return Err(Error::SignatureInvalid);
81 }
82
83 if constant_time_eq(&provided_signature, &expected_signature) {
84 Ok(())
85 } else {
86 Err(Error::SignatureInvalid)
87 }
88}
89
90fn verify_hs512(signing_input: &str, signature: &str, secret: &[u8]) -> Result<()> {
92 let provided_signature = base64url::decode_bytes(signature)?;
93
94 let mut mac = Hmac::<Sha512>::new_from_slice(secret).map_err(|_| Error::SignatureInvalid)?;
95 mac.update(signing_input.as_bytes());
96 let expected_signature = mac.finalize().into_bytes();
97
98 if provided_signature.len() != expected_signature.len() {
99 return Err(Error::SignatureInvalid);
100 }
101
102 if constant_time_eq(&provided_signature, &expected_signature) {
103 Ok(())
104 } else {
105 Err(Error::SignatureInvalid)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 fn compute_hs256_signature(signing_input: &str, secret: &[u8]) -> String {
114 let mut mac = Hmac::<Sha256>::new_from_slice(secret).unwrap();
115 mac.update(signing_input.as_bytes());
116 let signature_bytes = mac.finalize().into_bytes();
117 base64url::encode_bytes(&signature_bytes)
118 }
119
120 fn compute_hs384_signature(signing_input: &str, secret: &[u8]) -> String {
121 let mut mac = Hmac::<Sha384>::new_from_slice(secret).unwrap();
122 mac.update(signing_input.as_bytes());
123 let signature_bytes = mac.finalize().into_bytes();
124 base64url::encode_bytes(&signature_bytes)
125 }
126
127 fn compute_hs512_signature(signing_input: &str, secret: &[u8]) -> String {
128 let mut mac = Hmac::<Sha512>::new_from_slice(secret).unwrap();
129 mac.update(signing_input.as_bytes());
130 let signature_bytes = mac.finalize().into_bytes();
131 base64url::encode_bytes(&signature_bytes)
132 }
133
134 #[test]
135 fn test_hs256_valid_signature() {
136 let signing_input = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";
137 let secret = b"your-256-bit-secret";
138 let signature = compute_hs256_signature(signing_input, secret);
139
140 let key = Key::symmetric(secret.to_vec());
141 let result = HS256.verify(signing_input, &signature, &key);
142 assert!(result.is_ok());
143 }
144
145 #[test]
146 fn test_hs256_invalid_signature() {
147 let signing_input = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";
148 let secret = b"your-256-bit-secret";
149 let key = Key::symmetric(secret.to_vec());
150
151 let wrong_signature = base64url::encode("wrong");
152 let result = HS256.verify(signing_input, &wrong_signature, &key);
153 assert!(matches!(result, Err(Error::SignatureInvalid)));
154 }
155
156 #[test]
157 fn test_hs256_wrong_secret() {
158 let signing_input = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";
159 let secret = b"your-256-bit-secret";
160 let wrong_secret = b"wrong-secret";
161
162 let signature = compute_hs256_signature(signing_input, secret);
163 let key = Key::symmetric(wrong_secret.to_vec());
164
165 let result = HS256.verify(signing_input, &signature, &key);
166 assert!(matches!(result, Err(Error::SignatureInvalid)));
167 }
168
169 #[test]
170 fn test_hs384_valid_signature() {
171 let signing_input = "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";
172 let secret = b"your-384-bit-secret-needs-to-be-longer";
173 let signature = compute_hs384_signature(signing_input, secret);
174
175 let key = Key::symmetric(secret.to_vec());
176 let result = HS384.verify(signing_input, &signature, &key);
177 assert!(result.is_ok());
178 }
179
180 #[test]
181 fn test_hs512_valid_signature() {
182 let signing_input = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";
183 let secret = b"your-512-bit-secret-needs-to-be-even-longer-than-384-bit";
184 let signature = compute_hs512_signature(signing_input, secret);
185
186 let key = Key::symmetric(secret.to_vec());
187 let result = HS512.verify(signing_input, &signature, &key);
188 assert!(result.is_ok());
189 }
190
191 #[test]
192 #[allow(unused_variables)]
193 fn test_wrong_key_type() {
194 let signing_input = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";
195 let signature = "signature";
196
197 #[cfg(feature = "rsa")]
199 {
200 let rsa_key = Key::rsa_public(vec![1, 2, 3]);
201 let result = HS256.verify(signing_input, signature, &rsa_key);
202 assert!(matches!(result, Err(Error::KeyTypeMismatch { .. })));
203 }
204 }
205}