jwt_simple/algorithms/
hmac.rs

1use ct_codecs::{Base64UrlSafeNoPadding, Encoder};
2use hmac_sha512::sha384 as hmac_sha384;
3use rand::RngCore;
4use serde::{de::DeserializeOwned, Serialize};
5use zeroize::Zeroize;
6
7use crate::claims::*;
8use crate::common::*;
9#[cfg(feature = "cwt")]
10use crate::cwt_token::*;
11use crate::error::*;
12use crate::jwt_header::*;
13use crate::token::*;
14
15#[doc(hidden)]
16#[derive(Debug, Clone)]
17pub struct HMACKey {
18    raw_key: Vec<u8>,
19    metadata: Option<KeyMetadata>,
20}
21
22impl Drop for HMACKey {
23    fn drop(&mut self) {
24        self.raw_key.zeroize();
25    }
26}
27
28impl HMACKey {
29    pub fn from_bytes(raw_key: &[u8]) -> Self {
30        HMACKey {
31            raw_key: raw_key.to_vec(),
32            metadata: None,
33        }
34    }
35
36    pub fn to_bytes(&self) -> Vec<u8> {
37        self.raw_key.clone()
38    }
39
40    pub fn generate() -> Self {
41        let mut raw_key = vec![0u8; 32];
42        rand::thread_rng().fill_bytes(&mut raw_key);
43        HMACKey {
44            raw_key,
45            metadata: None,
46        }
47    }
48}
49
50impl AsRef<[u8]> for HMACKey {
51    fn as_ref(&self) -> &[u8] {
52        &self.raw_key
53    }
54}
55
56pub trait MACLike {
57    fn jwt_alg_name() -> &'static str;
58    fn key(&self) -> &HMACKey;
59    fn key_id(&self) -> &Option<String>;
60    fn set_key_id(&mut self, key_id: String);
61    fn metadata(&self) -> &Option<KeyMetadata>;
62    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error>;
63    fn authentication_tag(&self, authenticated: &str) -> Vec<u8>;
64
65    fn authenticate<CustomClaims: Serialize + DeserializeOwned>(
66        &self,
67        claims: JWTClaims<CustomClaims>,
68    ) -> Result<String, Error> {
69        let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
70            .with_metadata(self.metadata());
71        Token::build(&jwt_header, claims, |authenticated| {
72            Ok(self.authentication_tag(authenticated))
73        })
74    }
75
76    fn verify_token<CustomClaims: Serialize + DeserializeOwned>(
77        &self,
78        token: &str,
79        options: Option<VerificationOptions>,
80    ) -> Result<JWTClaims<CustomClaims>, Error> {
81        Token::verify(
82            Self::jwt_alg_name(),
83            token,
84            options,
85            |authenticated, authentication_tag| {
86                ensure!(
87                    timingsafe_eq(&self.authentication_tag(authenticated), authentication_tag),
88                    JWTError::InvalidAuthenticationTag
89                );
90                Ok(())
91            },
92        )
93    }
94
95    #[cfg(feature = "cwt")]
96    fn verify_cwt_token(
97        &self,
98        token: impl AsRef<[u8]>,
99        options: Option<VerificationOptions>,
100    ) -> Result<JWTClaims<NoCustomClaims>, Error> {
101        CWTToken::verify(
102            Self::jwt_alg_name(),
103            token,
104            options,
105            |authenticated, authentication_tag| {
106                ensure!(
107                    timingsafe_eq(&self.authentication_tag(authenticated), authentication_tag),
108                    JWTError::InvalidAuthenticationTag
109                );
110                Ok(())
111            },
112        )
113    }
114
115    fn create_key_id(&mut self) -> &str {
116        self.set_key_id(
117            Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
118                &self.key().to_bytes(),
119            ))
120            .unwrap(),
121        );
122        self.key_id().as_ref().map(|x| x.as_str()).unwrap()
123    }
124}
125
126#[derive(Debug, Clone)]
127pub struct HS256Key {
128    key: HMACKey,
129    key_id: Option<String>,
130}
131
132impl MACLike for HS256Key {
133    fn jwt_alg_name() -> &'static str {
134        "HS256"
135    }
136
137    fn key(&self) -> &HMACKey {
138        &self.key
139    }
140
141    fn key_id(&self) -> &Option<String> {
142        &self.key_id
143    }
144
145    fn set_key_id(&mut self, key_id: String) {
146        self.key_id = Some(key_id);
147    }
148
149    fn metadata(&self) -> &Option<KeyMetadata> {
150        &self.key.metadata
151    }
152
153    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
154        self.key.metadata = Some(metadata);
155        Ok(())
156    }
157
158    fn authentication_tag(&self, authenticated: &str) -> Vec<u8> {
159        hmac_sha256::HMAC::mac(authenticated.as_bytes(), self.key().as_ref()).to_vec()
160    }
161}
162
163impl HS256Key {
164    pub fn from_bytes(raw_key: &[u8]) -> Self {
165        HS256Key {
166            key: HMACKey::from_bytes(raw_key),
167            key_id: None,
168        }
169    }
170
171    pub fn to_bytes(&self) -> Vec<u8> {
172        self.key.to_bytes()
173    }
174
175    pub fn generate() -> Self {
176        HS256Key {
177            key: HMACKey::generate(),
178            key_id: None,
179        }
180    }
181
182    pub fn with_key_id(mut self, key_id: &str) -> Self {
183        self.key_id = Some(key_id.to_string());
184        self
185    }
186}
187
188#[derive(Debug, Clone)]
189pub struct HS512Key {
190    key: HMACKey,
191    key_id: Option<String>,
192}
193
194impl MACLike for HS512Key {
195    fn jwt_alg_name() -> &'static str {
196        "HS512"
197    }
198
199    fn key(&self) -> &HMACKey {
200        &self.key
201    }
202
203    fn key_id(&self) -> &Option<String> {
204        &self.key_id
205    }
206
207    fn set_key_id(&mut self, key_id: String) {
208        self.key_id = Some(key_id);
209    }
210
211    fn metadata(&self) -> &Option<KeyMetadata> {
212        &self.key.metadata
213    }
214
215    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
216        self.key.metadata = Some(metadata);
217        Ok(())
218    }
219
220    fn authentication_tag(&self, authenticated: &str) -> Vec<u8> {
221        hmac_sha512::HMAC::mac(authenticated.as_bytes(), self.key().as_ref()).to_vec()
222    }
223}
224
225impl HS512Key {
226    pub fn from_bytes(raw_key: &[u8]) -> Self {
227        HS512Key {
228            key: HMACKey::from_bytes(raw_key),
229            key_id: None,
230        }
231    }
232
233    pub fn to_bytes(&self) -> Vec<u8> {
234        self.key.to_bytes()
235    }
236
237    pub fn generate() -> Self {
238        HS512Key {
239            key: HMACKey::generate(),
240            key_id: None,
241        }
242    }
243
244    pub fn with_key_id(mut self, key_id: &str) -> Self {
245        self.key_id = Some(key_id.to_string());
246        self
247    }
248}
249
250#[derive(Debug, Clone)]
251pub struct HS384Key {
252    key: HMACKey,
253    key_id: Option<String>,
254}
255
256impl MACLike for HS384Key {
257    fn jwt_alg_name() -> &'static str {
258        "HS384"
259    }
260
261    fn key(&self) -> &HMACKey {
262        &self.key
263    }
264
265    fn key_id(&self) -> &Option<String> {
266        &self.key_id
267    }
268
269    fn set_key_id(&mut self, key_id: String) {
270        self.key_id = Some(key_id);
271    }
272
273    fn metadata(&self) -> &Option<KeyMetadata> {
274        &self.key.metadata
275    }
276
277    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
278        self.key.metadata = Some(metadata);
279        Ok(())
280    }
281
282    fn authentication_tag(&self, authenticated: &str) -> Vec<u8> {
283        hmac_sha384::HMAC::mac(authenticated.as_bytes(), self.key().as_ref()).to_vec()
284    }
285}
286
287impl HS384Key {
288    pub fn from_bytes(raw_key: &[u8]) -> Self {
289        HS384Key {
290            key: HMACKey::from_bytes(raw_key),
291            key_id: None,
292        }
293    }
294
295    pub fn to_bytes(&self) -> Vec<u8> {
296        self.key.to_bytes()
297    }
298
299    pub fn generate() -> Self {
300        HS384Key {
301            key: HMACKey::generate(),
302            key_id: None,
303        }
304    }
305
306    pub fn with_key_id(mut self, key_id: &str) -> Self {
307        self.key_id = Some(key_id.to_string());
308        self
309    }
310}