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    /// Create a HMAC key from a byte slice.
30    pub fn from_bytes(raw_key: &[u8]) -> Self {
31        HMACKey {
32            raw_key: raw_key.to_vec(),
33            metadata: None,
34        }
35    }
36
37    /// Convert the HMAC key to a byte slice.
38    pub fn to_bytes(&self) -> Vec<u8> {
39        self.raw_key.clone()
40    }
41
42    /// Get the salt associated with the key.
43    pub fn salt(&self) -> Option<Salt> {
44        self.metadata.as_ref().map(|metadata| metadata.salt.clone())
45    }
46
47    /// Set the salt associated with the key.
48    pub fn with_salt(mut self, salt: Salt) -> Self {
49        if let Some(metadata) = self.metadata.as_mut() {
50            metadata.salt = salt;
51        } else {
52            self.metadata = Some(KeyMetadata {
53                salt,
54                ..Default::default()
55            });
56        }
57        self
58    }
59
60    /// Generate a random HMAC key.
61    pub fn generate() -> Self {
62        let mut raw_key = vec![0u8; 32];
63        rand::thread_rng().fill_bytes(&mut raw_key);
64        HMACKey {
65            raw_key,
66            metadata: None,
67        }
68    }
69
70    /// Generate a random HMAC key with a random salt.
71    pub fn generate_with_salt() -> Self {
72        HMACKey::generate().with_salt(Salt::generate())
73    }
74}
75
76impl AsRef<[u8]> for HMACKey {
77    /// Get the raw key, as a byte slice
78    fn as_ref(&self) -> &[u8] {
79        &self.raw_key
80    }
81}
82
83pub trait MACLike {
84    fn jwt_alg_name() -> &'static str;
85    fn key(&self) -> &HMACKey;
86    fn key_id(&self) -> &Option<String>;
87    fn set_key_id(&mut self, key_id: String);
88    fn metadata(&self) -> &Option<KeyMetadata>;
89    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error>;
90    fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8>;
91
92    /// Get the salt associated with the key.
93    fn salt(&self) -> Salt {
94        self.metadata()
95            .as_ref()
96            .map(|metadata| metadata.salt.clone())
97            .unwrap_or(Salt::None)
98    }
99
100    /// Compute the salt to be used for verification, given a signer salt.
101    fn verifier_salt(&self) -> Result<Salt, Error> {
102        match self.metadata().as_ref().map(|metadata| &metadata.salt) {
103            None => bail!(JWTError::MissingSalt),
104            Some(Salt::Signer(salt)) => {
105                let authenticated_salt = self.authentication_tag(salt);
106                Ok(Salt::Verifier(authenticated_salt))
107            }
108            Some(x @ Salt::Verifier(_)) => Ok(x.clone()),
109            Some(Salt::None) => bail!(JWTError::MissingSalt),
110        }
111    }
112
113    /// Attach a salt to the key.
114    fn attach_salt(&mut self, salt: Salt) -> Result<(), Error> {
115        let metadata = KeyMetadata {
116            salt,
117            ..Default::default()
118        };
119        self.attach_metadata(metadata).unwrap();
120        Ok(())
121    }
122
123    /// Authenticate a token.
124    fn authenticate<CustomClaims: Serialize + DeserializeOwned>(
125        &self,
126        claims: JWTClaims<CustomClaims>,
127    ) -> Result<String, Error> {
128        let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
129            .with_key_metadata(self.metadata());
130        Token::build(&jwt_header, claims, |authenticated| {
131            Ok(self.authentication_tag(authenticated.as_bytes()))
132        })
133    }
134
135    /// Verify a token.
136    fn verify_token<CustomClaims: Serialize + DeserializeOwned>(
137        &self,
138        token: &str,
139        options: Option<VerificationOptions>,
140    ) -> Result<JWTClaims<CustomClaims>, Error> {
141        Token::verify(
142            Self::jwt_alg_name(),
143            token,
144            options,
145            |authenticated, authentication_tag| {
146                ensure!(
147                    timingsafe_eq(
148                        &self.authentication_tag(authenticated.as_bytes()),
149                        authentication_tag
150                    ),
151                    JWTError::InvalidAuthenticationTag
152                );
153                Ok(())
154            },
155            |salt: Option<&[u8]>| {
156                if let Some(Salt::Verifier(authenticated_salt)) =
157                    self.metadata().as_ref().map(|metadata| &metadata.salt)
158                {
159                    match salt {
160                        None => bail!(JWTError::MissingSalt),
161                        Some(salt) => {
162                            let expected_authenticated_tag = self.authentication_tag(salt);
163                            ensure!(
164                                timingsafe_eq(authenticated_salt, &expected_authenticated_tag),
165                                JWTError::InvalidAuthenticationTag
166                            );
167                        }
168                    }
169                } else {
170                    ensure!(salt.is_none(), JWTError::MissingSalt);
171                }
172                Ok(())
173            },
174        )
175    }
176
177    #[cfg(feature = "cwt")]
178    fn verify_cwt_token(
179        &self,
180        token: impl AsRef<[u8]>,
181        options: Option<VerificationOptions>,
182    ) -> Result<JWTClaims<NoCustomClaims>, Error> {
183        CWTToken::verify(
184            Self::jwt_alg_name(),
185            token,
186            options,
187            |authenticated, authentication_tag| {
188                ensure!(
189                    timingsafe_eq(
190                        &self.authentication_tag(authenticated.as_bytes()),
191                        authentication_tag
192                    ),
193                    JWTError::InvalidAuthenticationTag
194                );
195                Ok(())
196            },
197        )
198    }
199
200    fn create_key_id(&mut self) -> &str {
201        self.set_key_id(
202            Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
203                &self.key().to_bytes(),
204            ))
205            .unwrap(),
206        );
207        self.key_id().as_ref().map(|x| x.as_str()).unwrap()
208    }
209}
210
211#[derive(Debug, Clone)]
212pub struct HS256Key {
213    key: HMACKey,
214    key_id: Option<String>,
215}
216
217impl MACLike for HS256Key {
218    fn jwt_alg_name() -> &'static str {
219        "HS256"
220    }
221
222    fn key(&self) -> &HMACKey {
223        &self.key
224    }
225
226    fn key_id(&self) -> &Option<String> {
227        &self.key_id
228    }
229
230    fn set_key_id(&mut self, key_id: String) {
231        self.key_id = Some(key_id);
232    }
233
234    fn metadata(&self) -> &Option<KeyMetadata> {
235        &self.key.metadata
236    }
237
238    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
239        self.key.metadata = Some(metadata);
240        Ok(())
241    }
242
243    fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
244        hmac_sha256::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
245    }
246}
247
248impl HS256Key {
249    pub fn from_bytes(raw_key: &[u8]) -> Self {
250        HS256Key {
251            key: HMACKey::from_bytes(raw_key),
252            key_id: None,
253        }
254    }
255
256    pub fn to_bytes(&self) -> Vec<u8> {
257        self.key.to_bytes()
258    }
259
260    pub fn generate() -> Self {
261        HS256Key {
262            key: HMACKey::generate(),
263            key_id: None,
264        }
265    }
266
267    pub fn generate_with_salt() -> Self {
268        HS256Key {
269            key: HMACKey::generate_with_salt(),
270            key_id: None,
271        }
272    }
273
274    pub fn with_key_id(mut self, key_id: &str) -> Self {
275        self.key_id = Some(key_id.to_string());
276        self
277    }
278}
279
280#[derive(Debug, Clone)]
281pub struct HS512Key {
282    key: HMACKey,
283    key_id: Option<String>,
284}
285
286impl MACLike for HS512Key {
287    fn jwt_alg_name() -> &'static str {
288        "HS512"
289    }
290
291    fn key(&self) -> &HMACKey {
292        &self.key
293    }
294
295    fn key_id(&self) -> &Option<String> {
296        &self.key_id
297    }
298
299    fn set_key_id(&mut self, key_id: String) {
300        self.key_id = Some(key_id);
301    }
302
303    fn metadata(&self) -> &Option<KeyMetadata> {
304        &self.key.metadata
305    }
306
307    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
308        self.key.metadata = Some(metadata);
309        Ok(())
310    }
311
312    fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
313        hmac_sha512::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
314    }
315}
316
317impl HS512Key {
318    pub fn from_bytes(raw_key: &[u8]) -> Self {
319        HS512Key {
320            key: HMACKey::from_bytes(raw_key),
321            key_id: None,
322        }
323    }
324
325    pub fn to_bytes(&self) -> Vec<u8> {
326        self.key.to_bytes()
327    }
328
329    pub fn generate() -> Self {
330        HS512Key {
331            key: HMACKey::generate(),
332            key_id: None,
333        }
334    }
335
336    pub fn generate_with_salt() -> Self {
337        HS512Key {
338            key: HMACKey::generate_with_salt(),
339            key_id: None,
340        }
341    }
342
343    pub fn with_key_id(mut self, key_id: &str) -> Self {
344        self.key_id = Some(key_id.to_string());
345        self
346    }
347}
348
349#[derive(Debug, Clone)]
350pub struct HS384Key {
351    key: HMACKey,
352    key_id: Option<String>,
353}
354
355impl MACLike for HS384Key {
356    fn jwt_alg_name() -> &'static str {
357        "HS384"
358    }
359
360    fn key(&self) -> &HMACKey {
361        &self.key
362    }
363
364    fn key_id(&self) -> &Option<String> {
365        &self.key_id
366    }
367
368    fn set_key_id(&mut self, key_id: String) {
369        self.key_id = Some(key_id);
370    }
371
372    fn metadata(&self) -> &Option<KeyMetadata> {
373        &self.key.metadata
374    }
375
376    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
377        self.key.metadata = Some(metadata);
378        Ok(())
379    }
380
381    fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
382        hmac_sha384::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
383    }
384}
385
386impl HS384Key {
387    pub fn from_bytes(raw_key: &[u8]) -> Self {
388        HS384Key {
389            key: HMACKey::from_bytes(raw_key),
390            key_id: None,
391        }
392    }
393
394    pub fn to_bytes(&self) -> Vec<u8> {
395        self.key.to_bytes()
396    }
397
398    pub fn generate() -> Self {
399        HS384Key {
400            key: HMACKey::generate(),
401            key_id: None,
402        }
403    }
404
405    pub fn generate_with_salt() -> Self {
406        HS384Key {
407            key: HMACKey::generate_with_salt(),
408            key_id: None,
409        }
410    }
411
412    pub fn with_key_id(mut self, key_id: &str) -> Self {
413        self.key_id = Some(key_id.to_string());
414        self
415    }
416}
417
418//
419
420#[derive(Debug, Clone)]
421pub struct Blake2bKey {
422    key: HMACKey,
423    key_id: Option<String>,
424}
425
426impl MACLike for Blake2bKey {
427    fn jwt_alg_name() -> &'static str {
428        "BLAKE2B"
429    }
430
431    fn key(&self) -> &HMACKey {
432        &self.key
433    }
434
435    fn key_id(&self) -> &Option<String> {
436        &self.key_id
437    }
438
439    fn set_key_id(&mut self, key_id: String) {
440        self.key_id = Some(key_id);
441    }
442
443    fn metadata(&self) -> &Option<KeyMetadata> {
444        &self.key.metadata
445    }
446
447    fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
448        self.key.metadata = Some(metadata);
449        Ok(())
450    }
451
452    fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
453        blake2b_simd::Params::new()
454            .hash_length(32)
455            .key(self.key().as_ref())
456            .to_state()
457            .update(authenticated)
458            .finalize()
459            .as_bytes()
460            .to_vec()
461    }
462}
463
464impl Blake2bKey {
465    pub fn from_bytes(raw_key: &[u8]) -> Self {
466        Blake2bKey {
467            key: HMACKey::from_bytes(raw_key),
468            key_id: None,
469        }
470    }
471
472    pub fn to_bytes(&self) -> Vec<u8> {
473        self.key.to_bytes()
474    }
475
476    pub fn generate() -> Self {
477        Blake2bKey {
478            key: HMACKey::generate(),
479            key_id: None,
480        }
481    }
482
483    pub fn generate_with_salt() -> Self {
484        Blake2bKey {
485            key: HMACKey::generate_with_salt(),
486            key_id: None,
487        }
488    }
489
490    pub fn with_key_id(mut self, key_id: &str) -> Self {
491        self.key_id = Some(key_id.to_string());
492        self
493    }
494}