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 {
31 HMACKey {
32 raw_key: raw_key.to_vec(),
33 metadata: None,
34 }
35 }
36
37 pub fn to_bytes(&self) -> Vec<u8> {
39 self.raw_key.clone()
40 }
41
42 pub fn salt(&self) -> Option<Salt> {
44 self.metadata.as_ref().map(|metadata| metadata.salt.clone())
45 }
46
47 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 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 pub fn generate_with_salt() -> Self {
72 HMACKey::generate().with_salt(Salt::generate())
73 }
74}
75
76impl AsRef<[u8]> for HMACKey {
77 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 fn salt(&self) -> Salt {
94 self.metadata()
95 .as_ref()
96 .map(|metadata| metadata.salt.clone())
97 .unwrap_or(Salt::None)
98 }
99
100 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 fn attach_salt(&mut self, salt: Salt) -> Result<(), Error> {
115 let metadata = KeyMetadata {
116 salt,
117 ..Default::default()
118 };
119 self.attach_metadata(metadata)?;
120 Ok(())
121 }
122
123 fn authenticate<CustomClaims: Serialize>(
125 &self,
126 claims: JWTClaims<CustomClaims>,
127 ) -> Result<String, Error> {
128 self.authenticate_with_options(claims, &Default::default())
129 }
130
131 fn authenticate_with_options<CustomClaims: Serialize>(
132 &self,
133 claims: JWTClaims<CustomClaims>,
134 options: &HeaderOptions,
135 ) -> Result<String, Error> {
136 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
137 let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
138 .with_key_metadata(self.metadata())
139 .with_options(options);
140 Token::build(&jwt_header, claims, |authenticated| {
141 Ok(self.authentication_tag(authenticated.as_bytes()))
142 })
143 }
144
145 fn verify_token<CustomClaims: DeserializeOwned>(
147 &self,
148 token: &str,
149 options: Option<VerificationOptions>,
150 ) -> Result<JWTClaims<CustomClaims>, Error> {
151 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
152 Token::verify(
153 Self::jwt_alg_name(),
154 token,
155 options,
156 |authenticated, authentication_tag| {
157 ensure!(
158 ct_codecs::verify(
159 &self.authentication_tag(authenticated.as_bytes()),
160 authentication_tag
161 ),
162 JWTError::InvalidAuthenticationTag
163 );
164 Ok(())
165 },
166 |salt: Option<&[u8]>| {
167 if let Some(Salt::Verifier(authenticated_salt)) =
168 self.metadata().as_ref().map(|metadata| &metadata.salt)
169 {
170 match salt {
171 None => bail!(JWTError::MissingSalt),
172 Some(salt) => {
173 let expected_authenticated_tag = self.authentication_tag(salt);
174 ensure!(
175 ct_codecs::verify(authenticated_salt, &expected_authenticated_tag),
176 JWTError::InvalidAuthenticationTag
177 );
178 }
179 }
180 } else {
181 ensure!(salt.is_none(), JWTError::MissingSalt);
182 }
183 Ok(())
184 },
185 )
186 }
187
188 #[cfg(feature = "cwt")]
189 fn verify_cwt_token(
190 &self,
191 token: impl AsRef<[u8]>,
192 options: Option<VerificationOptions>,
193 ) -> Result<JWTClaims<NoCustomClaims>, Error> {
194 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
195 CWTToken::verify(
196 Self::jwt_alg_name(),
197 token,
198 options,
199 |authenticated, authentication_tag| {
200 ensure!(
201 ct_codecs::verify(
202 &self.authentication_tag(authenticated.as_bytes()),
203 authentication_tag
204 ),
205 JWTError::InvalidAuthenticationTag
206 );
207 Ok(())
208 },
209 )
210 }
211
212 #[cfg(feature = "cwt")]
260 fn verify_cwt_token_with_custom_claims<CustomClaims>(
261 &self,
262 token: impl AsRef<[u8]>,
263 options: Option<VerificationOptions>,
264 ) -> Result<JWTClaims<CustomClaims>, Error>
265 where
266 CustomClaims: DeserializeOwned + Default,
267 {
268 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
269 CWTToken::verify(
270 Self::jwt_alg_name(),
271 token,
272 options,
273 |authenticated, authentication_tag| {
274 ensure!(
275 ct_codecs::verify(
276 &self.authentication_tag(authenticated.as_bytes()),
277 authentication_tag
278 ),
279 JWTError::InvalidAuthenticationTag
280 );
281 Ok(())
282 },
283 )
284 }
285
286 #[cfg(feature = "cwt")]
288 fn decode_cwt_metadata(&self, token: impl AsRef<[u8]>) -> Result<TokenMetadata, Error> {
289 CWTToken::decode_metadata(token)
290 }
291
292 fn create_key_id(&mut self) -> &str {
293 self.set_key_id(
294 Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
295 &self.key().to_bytes(),
296 ))
297 .unwrap(),
298 );
299 self.key_id().as_ref().map(|x| x.as_str()).unwrap()
300 }
301}
302
303#[derive(Debug, Clone)]
304pub struct HS256Key {
305 key: HMACKey,
306 key_id: Option<String>,
307}
308
309impl MACLike for HS256Key {
310 fn jwt_alg_name() -> &'static str {
311 "HS256"
312 }
313
314 fn key(&self) -> &HMACKey {
315 &self.key
316 }
317
318 fn key_id(&self) -> &Option<String> {
319 &self.key_id
320 }
321
322 fn set_key_id(&mut self, key_id: String) {
323 self.key_id = Some(key_id);
324 }
325
326 fn metadata(&self) -> &Option<KeyMetadata> {
327 &self.key.metadata
328 }
329
330 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
331 self.key.metadata = Some(metadata);
332 Ok(())
333 }
334
335 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
336 hmac_sha256::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
337 }
338}
339
340impl HS256Key {
341 pub fn from_bytes(raw_key: &[u8]) -> Self {
342 HS256Key {
343 key: HMACKey::from_bytes(raw_key),
344 key_id: None,
345 }
346 }
347
348 pub fn to_bytes(&self) -> Vec<u8> {
349 self.key.to_bytes()
350 }
351
352 pub fn generate() -> Self {
353 HS256Key {
354 key: HMACKey::generate(),
355 key_id: None,
356 }
357 }
358
359 pub fn generate_with_salt() -> Self {
360 HS256Key {
361 key: HMACKey::generate_with_salt(),
362 key_id: None,
363 }
364 }
365
366 pub fn with_key_id(mut self, key_id: &str) -> Self {
367 self.key_id = Some(key_id.to_string());
368 self
369 }
370
371 #[cfg(feature = "cwt")]
419 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
420 &self,
421 token: impl AsRef<[u8]>,
422 options: Option<VerificationOptions>,
423 ) -> Result<JWTClaims<CustomClaims>, Error>
424 where
425 CustomClaims: DeserializeOwned + Default,
426 {
427 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
428 }
429}
430
431#[derive(Debug, Clone)]
432pub struct HS512Key {
433 key: HMACKey,
434 key_id: Option<String>,
435}
436
437impl MACLike for HS512Key {
438 fn jwt_alg_name() -> &'static str {
439 "HS512"
440 }
441
442 fn key(&self) -> &HMACKey {
443 &self.key
444 }
445
446 fn key_id(&self) -> &Option<String> {
447 &self.key_id
448 }
449
450 fn set_key_id(&mut self, key_id: String) {
451 self.key_id = Some(key_id);
452 }
453
454 fn metadata(&self) -> &Option<KeyMetadata> {
455 &self.key.metadata
456 }
457
458 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
459 self.key.metadata = Some(metadata);
460 Ok(())
461 }
462
463 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
464 hmac_sha512::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
465 }
466}
467
468impl HS512Key {
469 pub fn from_bytes(raw_key: &[u8]) -> Self {
470 HS512Key {
471 key: HMACKey::from_bytes(raw_key),
472 key_id: None,
473 }
474 }
475
476 pub fn to_bytes(&self) -> Vec<u8> {
477 self.key.to_bytes()
478 }
479
480 pub fn generate() -> Self {
481 HS512Key {
482 key: HMACKey::generate(),
483 key_id: None,
484 }
485 }
486
487 pub fn generate_with_salt() -> Self {
488 HS512Key {
489 key: HMACKey::generate_with_salt(),
490 key_id: None,
491 }
492 }
493
494 pub fn with_key_id(mut self, key_id: &str) -> Self {
495 self.key_id = Some(key_id.to_string());
496 self
497 }
498
499 #[cfg(feature = "cwt")]
518 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
519 &self,
520 token: impl AsRef<[u8]>,
521 options: Option<VerificationOptions>,
522 ) -> Result<JWTClaims<CustomClaims>, Error>
523 where
524 CustomClaims: DeserializeOwned + Default,
525 {
526 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
527 }
528}
529
530#[derive(Debug, Clone)]
531pub struct HS384Key {
532 key: HMACKey,
533 key_id: Option<String>,
534}
535
536impl MACLike for HS384Key {
537 fn jwt_alg_name() -> &'static str {
538 "HS384"
539 }
540
541 fn key(&self) -> &HMACKey {
542 &self.key
543 }
544
545 fn key_id(&self) -> &Option<String> {
546 &self.key_id
547 }
548
549 fn set_key_id(&mut self, key_id: String) {
550 self.key_id = Some(key_id);
551 }
552
553 fn metadata(&self) -> &Option<KeyMetadata> {
554 &self.key.metadata
555 }
556
557 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
558 self.key.metadata = Some(metadata);
559 Ok(())
560 }
561
562 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
563 hmac_sha384::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
564 }
565}
566
567impl HS384Key {
568 pub fn from_bytes(raw_key: &[u8]) -> Self {
569 HS384Key {
570 key: HMACKey::from_bytes(raw_key),
571 key_id: None,
572 }
573 }
574
575 pub fn to_bytes(&self) -> Vec<u8> {
576 self.key.to_bytes()
577 }
578
579 pub fn generate() -> Self {
580 HS384Key {
581 key: HMACKey::generate(),
582 key_id: None,
583 }
584 }
585
586 pub fn generate_with_salt() -> Self {
587 HS384Key {
588 key: HMACKey::generate_with_salt(),
589 key_id: None,
590 }
591 }
592
593 pub fn with_key_id(mut self, key_id: &str) -> Self {
594 self.key_id = Some(key_id.to_string());
595 self
596 }
597
598 #[cfg(feature = "cwt")]
617 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
618 &self,
619 token: impl AsRef<[u8]>,
620 options: Option<VerificationOptions>,
621 ) -> Result<JWTClaims<CustomClaims>, Error>
622 where
623 CustomClaims: DeserializeOwned + Default,
624 {
625 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
626 }
627}
628
629#[derive(Debug, Clone)]
632pub struct Blake2bKey {
633 key: HMACKey,
634 key_id: Option<String>,
635}
636
637impl MACLike for Blake2bKey {
638 fn jwt_alg_name() -> &'static str {
639 "BLAKE2B"
640 }
641
642 fn key(&self) -> &HMACKey {
643 &self.key
644 }
645
646 fn key_id(&self) -> &Option<String> {
647 &self.key_id
648 }
649
650 fn set_key_id(&mut self, key_id: String) {
651 self.key_id = Some(key_id);
652 }
653
654 fn metadata(&self) -> &Option<KeyMetadata> {
655 &self.key.metadata
656 }
657
658 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
659 self.key.metadata = Some(metadata);
660 Ok(())
661 }
662
663 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
664 blake2b_simd::Params::new()
665 .hash_length(32)
666 .key(self.key().as_ref())
667 .to_state()
668 .update(authenticated)
669 .finalize()
670 .as_bytes()
671 .to_vec()
672 }
673}
674
675impl Blake2bKey {
676 pub fn from_bytes(raw_key: &[u8]) -> Self {
677 Blake2bKey {
678 key: HMACKey::from_bytes(raw_key),
679 key_id: None,
680 }
681 }
682
683 pub fn to_bytes(&self) -> Vec<u8> {
684 self.key.to_bytes()
685 }
686
687 pub fn generate() -> Self {
688 Blake2bKey {
689 key: HMACKey::generate(),
690 key_id: None,
691 }
692 }
693
694 #[cfg(feature = "cwt")]
713 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
714 &self,
715 token: impl AsRef<[u8]>,
716 options: Option<VerificationOptions>,
717 ) -> Result<JWTClaims<CustomClaims>, Error>
718 where
719 CustomClaims: DeserializeOwned + Default,
720 {
721 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
722 }
723
724 pub fn generate_with_salt() -> Self {
725 Blake2bKey {
726 key: HMACKey::generate_with_salt(),
727 key_id: None,
728 }
729 }
730
731 pub fn with_key_id(mut self, key_id: &str) -> Self {
732 self.key_id = Some(key_id.to_string());
733 self
734 }
735}