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(Clone)]
17pub struct HMACKey {
18 raw_key: Vec<u8>,
19 metadata: Option<KeyMetadata>,
20}
21
22impl std::fmt::Debug for HMACKey {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(f, "HMACKey")
25 }
26}
27
28impl Drop for HMACKey {
29 fn drop(&mut self) {
30 self.raw_key.zeroize();
31 }
32}
33
34impl HMACKey {
35 pub fn from_bytes(raw_key: &[u8]) -> Self {
37 HMACKey {
38 raw_key: raw_key.to_vec(),
39 metadata: None,
40 }
41 }
42
43 pub fn to_bytes(&self) -> Vec<u8> {
45 self.raw_key.clone()
46 }
47
48 pub fn salt(&self) -> Option<Salt> {
50 self.metadata.as_ref().map(|metadata| metadata.salt.clone())
51 }
52
53 pub fn with_salt(mut self, salt: Salt) -> Self {
55 if let Some(metadata) = self.metadata.as_mut() {
56 metadata.salt = salt;
57 } else {
58 self.metadata = Some(KeyMetadata {
59 salt,
60 ..Default::default()
61 });
62 }
63 self
64 }
65
66 pub fn generate() -> Self {
68 let mut raw_key = vec![0u8; 32];
69 rand::thread_rng().fill_bytes(&mut raw_key);
70 HMACKey {
71 raw_key,
72 metadata: None,
73 }
74 }
75
76 pub fn generate_with_salt() -> Self {
78 HMACKey::generate().with_salt(Salt::generate())
79 }
80}
81
82impl AsRef<[u8]> for HMACKey {
83 fn as_ref(&self) -> &[u8] {
85 &self.raw_key
86 }
87}
88
89pub trait MACLike {
90 fn jwt_alg_name() -> &'static str;
91 fn key(&self) -> &HMACKey;
92 fn key_id(&self) -> &Option<String>;
93 fn set_key_id(&mut self, key_id: String);
94 fn metadata(&self) -> &Option<KeyMetadata>;
95 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error>;
96 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8>;
97
98 fn salt(&self) -> Salt {
100 self.metadata()
101 .as_ref()
102 .map(|metadata| metadata.salt.clone())
103 .unwrap_or(Salt::None)
104 }
105
106 fn verifier_salt(&self) -> Result<Salt, Error> {
108 match self.metadata().as_ref().map(|metadata| &metadata.salt) {
109 None => bail!(JWTError::MissingSalt),
110 Some(Salt::Signer(salt)) => {
111 let authenticated_salt = self.authentication_tag(salt);
112 Ok(Salt::Verifier(authenticated_salt))
113 }
114 Some(x @ Salt::Verifier(_)) => Ok(x.clone()),
115 Some(Salt::None) => bail!(JWTError::MissingSalt),
116 }
117 }
118
119 fn attach_salt(&mut self, salt: Salt) -> Result<(), Error> {
121 let metadata = KeyMetadata {
122 salt,
123 ..Default::default()
124 };
125 self.attach_metadata(metadata)?;
126 Ok(())
127 }
128
129 fn authenticate<CustomClaims: Serialize>(
131 &self,
132 claims: JWTClaims<CustomClaims>,
133 ) -> Result<String, Error> {
134 self.authenticate_with_options(claims, &Default::default())
135 }
136
137 fn authenticate_with_options<CustomClaims: Serialize>(
138 &self,
139 claims: JWTClaims<CustomClaims>,
140 options: &HeaderOptions,
141 ) -> Result<String, Error> {
142 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
143 let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
144 .with_key_metadata(self.metadata())
145 .with_options(options);
146 Token::build(&jwt_header, claims, |authenticated| {
147 Ok(self.authentication_tag(authenticated.as_bytes()))
148 })
149 }
150
151 fn verify_token<CustomClaims: DeserializeOwned>(
153 &self,
154 token: &str,
155 options: Option<VerificationOptions>,
156 ) -> Result<JWTClaims<CustomClaims>, Error> {
157 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
158 Token::verify(
159 Self::jwt_alg_name(),
160 token,
161 options,
162 |authenticated, authentication_tag| {
163 ensure!(
164 ct_codecs::verify(
165 &self.authentication_tag(authenticated.as_bytes()),
166 authentication_tag
167 ),
168 JWTError::InvalidAuthenticationTag
169 );
170 Ok(())
171 },
172 |salt: Option<&[u8]>| {
173 if let Some(Salt::Verifier(authenticated_salt)) =
174 self.metadata().as_ref().map(|metadata| &metadata.salt)
175 {
176 match salt {
177 None => bail!(JWTError::MissingSalt),
178 Some(salt) => {
179 let expected_authenticated_tag = self.authentication_tag(salt);
180 ensure!(
181 ct_codecs::verify(authenticated_salt, &expected_authenticated_tag),
182 JWTError::InvalidAuthenticationTag
183 );
184 }
185 }
186 } else {
187 ensure!(salt.is_none(), JWTError::MissingSalt);
188 }
189 Ok(())
190 },
191 )
192 }
193
194 #[cfg(feature = "cwt")]
195 fn verify_cwt_token(
196 &self,
197 token: impl AsRef<[u8]>,
198 options: Option<VerificationOptions>,
199 ) -> Result<JWTClaims<NoCustomClaims>, Error> {
200 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
201 CWTToken::verify(
202 Self::jwt_alg_name(),
203 token,
204 options,
205 |authenticated, authentication_tag| {
206 ensure!(
207 ct_codecs::verify(
208 &self.authentication_tag(authenticated.as_bytes()),
209 authentication_tag
210 ),
211 JWTError::InvalidAuthenticationTag
212 );
213 Ok(())
214 },
215 )
216 }
217
218 #[cfg(feature = "cwt")]
266 fn verify_cwt_token_with_custom_claims<CustomClaims>(
267 &self,
268 token: impl AsRef<[u8]>,
269 options: Option<VerificationOptions>,
270 ) -> Result<JWTClaims<CustomClaims>, Error>
271 where
272 CustomClaims: DeserializeOwned + Default,
273 {
274 ensure!(self.key().as_ref().len() >= 12, JWTError::WeakKey);
275 CWTToken::verify(
276 Self::jwt_alg_name(),
277 token,
278 options,
279 |authenticated, authentication_tag| {
280 ensure!(
281 ct_codecs::verify(
282 &self.authentication_tag(authenticated.as_bytes()),
283 authentication_tag
284 ),
285 JWTError::InvalidAuthenticationTag
286 );
287 Ok(())
288 },
289 )
290 }
291
292 #[cfg(feature = "cwt")]
294 fn decode_cwt_metadata(&self, token: impl AsRef<[u8]>) -> Result<TokenMetadata, Error> {
295 CWTToken::decode_metadata(token)
296 }
297
298 fn create_key_id(&mut self) -> &str {
299 self.set_key_id(
300 Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
301 &self.key().to_bytes(),
302 ))
303 .unwrap(),
304 );
305 self.key_id().as_ref().map(|x| x.as_str()).unwrap()
306 }
307}
308
309#[derive(Debug, Clone)]
310pub struct HS256Key {
311 key: HMACKey,
312 key_id: Option<String>,
313}
314
315impl MACLike for HS256Key {
316 fn jwt_alg_name() -> &'static str {
317 "HS256"
318 }
319
320 fn key(&self) -> &HMACKey {
321 &self.key
322 }
323
324 fn key_id(&self) -> &Option<String> {
325 &self.key_id
326 }
327
328 fn set_key_id(&mut self, key_id: String) {
329 self.key_id = Some(key_id);
330 }
331
332 fn metadata(&self) -> &Option<KeyMetadata> {
333 &self.key.metadata
334 }
335
336 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
337 self.key.metadata = Some(metadata);
338 Ok(())
339 }
340
341 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
342 hmac_sha256::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
343 }
344}
345
346impl HS256Key {
347 pub fn from_bytes(raw_key: &[u8]) -> Self {
348 HS256Key {
349 key: HMACKey::from_bytes(raw_key),
350 key_id: None,
351 }
352 }
353
354 pub fn to_bytes(&self) -> Vec<u8> {
355 self.key.to_bytes()
356 }
357
358 pub fn generate() -> Self {
359 HS256Key {
360 key: HMACKey::generate(),
361 key_id: None,
362 }
363 }
364
365 pub fn generate_with_salt() -> Self {
366 HS256Key {
367 key: HMACKey::generate_with_salt(),
368 key_id: None,
369 }
370 }
371
372 pub fn with_key_id(mut self, key_id: &str) -> Self {
373 self.key_id = Some(key_id.to_string());
374 self
375 }
376
377 #[cfg(feature = "cwt")]
425 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
426 &self,
427 token: impl AsRef<[u8]>,
428 options: Option<VerificationOptions>,
429 ) -> Result<JWTClaims<CustomClaims>, Error>
430 where
431 CustomClaims: DeserializeOwned + Default,
432 {
433 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
434 }
435}
436
437#[derive(Debug, Clone)]
438pub struct HS512Key {
439 key: HMACKey,
440 key_id: Option<String>,
441}
442
443impl MACLike for HS512Key {
444 fn jwt_alg_name() -> &'static str {
445 "HS512"
446 }
447
448 fn key(&self) -> &HMACKey {
449 &self.key
450 }
451
452 fn key_id(&self) -> &Option<String> {
453 &self.key_id
454 }
455
456 fn set_key_id(&mut self, key_id: String) {
457 self.key_id = Some(key_id);
458 }
459
460 fn metadata(&self) -> &Option<KeyMetadata> {
461 &self.key.metadata
462 }
463
464 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
465 self.key.metadata = Some(metadata);
466 Ok(())
467 }
468
469 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
470 hmac_sha512::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
471 }
472}
473
474impl HS512Key {
475 pub fn from_bytes(raw_key: &[u8]) -> Self {
476 HS512Key {
477 key: HMACKey::from_bytes(raw_key),
478 key_id: None,
479 }
480 }
481
482 pub fn to_bytes(&self) -> Vec<u8> {
483 self.key.to_bytes()
484 }
485
486 pub fn generate() -> Self {
487 HS512Key {
488 key: HMACKey::generate(),
489 key_id: None,
490 }
491 }
492
493 pub fn generate_with_salt() -> Self {
494 HS512Key {
495 key: HMACKey::generate_with_salt(),
496 key_id: None,
497 }
498 }
499
500 pub fn with_key_id(mut self, key_id: &str) -> Self {
501 self.key_id = Some(key_id.to_string());
502 self
503 }
504
505 #[cfg(feature = "cwt")]
524 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
525 &self,
526 token: impl AsRef<[u8]>,
527 options: Option<VerificationOptions>,
528 ) -> Result<JWTClaims<CustomClaims>, Error>
529 where
530 CustomClaims: DeserializeOwned + Default,
531 {
532 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
533 }
534}
535
536#[derive(Debug, Clone)]
537pub struct HS384Key {
538 key: HMACKey,
539 key_id: Option<String>,
540}
541
542impl MACLike for HS384Key {
543 fn jwt_alg_name() -> &'static str {
544 "HS384"
545 }
546
547 fn key(&self) -> &HMACKey {
548 &self.key
549 }
550
551 fn key_id(&self) -> &Option<String> {
552 &self.key_id
553 }
554
555 fn set_key_id(&mut self, key_id: String) {
556 self.key_id = Some(key_id);
557 }
558
559 fn metadata(&self) -> &Option<KeyMetadata> {
560 &self.key.metadata
561 }
562
563 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
564 self.key.metadata = Some(metadata);
565 Ok(())
566 }
567
568 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
569 hmac_sha384::HMAC::mac(authenticated, self.key().as_ref()).to_vec()
570 }
571}
572
573impl HS384Key {
574 pub fn from_bytes(raw_key: &[u8]) -> Self {
575 HS384Key {
576 key: HMACKey::from_bytes(raw_key),
577 key_id: None,
578 }
579 }
580
581 pub fn to_bytes(&self) -> Vec<u8> {
582 self.key.to_bytes()
583 }
584
585 pub fn generate() -> Self {
586 HS384Key {
587 key: HMACKey::generate(),
588 key_id: None,
589 }
590 }
591
592 pub fn generate_with_salt() -> Self {
593 HS384Key {
594 key: HMACKey::generate_with_salt(),
595 key_id: None,
596 }
597 }
598
599 pub fn with_key_id(mut self, key_id: &str) -> Self {
600 self.key_id = Some(key_id.to_string());
601 self
602 }
603
604 #[cfg(feature = "cwt")]
623 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
624 &self,
625 token: impl AsRef<[u8]>,
626 options: Option<VerificationOptions>,
627 ) -> Result<JWTClaims<CustomClaims>, Error>
628 where
629 CustomClaims: DeserializeOwned + Default,
630 {
631 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
632 }
633}
634
635#[derive(Debug, Clone)]
638pub struct Blake2bKey {
639 key: HMACKey,
640 key_id: Option<String>,
641}
642
643impl MACLike for Blake2bKey {
644 fn jwt_alg_name() -> &'static str {
645 "BLAKE2B"
646 }
647
648 fn key(&self) -> &HMACKey {
649 &self.key
650 }
651
652 fn key_id(&self) -> &Option<String> {
653 &self.key_id
654 }
655
656 fn set_key_id(&mut self, key_id: String) {
657 self.key_id = Some(key_id);
658 }
659
660 fn metadata(&self) -> &Option<KeyMetadata> {
661 &self.key.metadata
662 }
663
664 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
665 self.key.metadata = Some(metadata);
666 Ok(())
667 }
668
669 fn authentication_tag(&self, authenticated: &[u8]) -> Vec<u8> {
670 blake2b_simd::Params::new()
671 .hash_length(32)
672 .key(self.key().as_ref())
673 .to_state()
674 .update(authenticated)
675 .finalize()
676 .as_bytes()
677 .to_vec()
678 }
679}
680
681impl Blake2bKey {
682 pub fn from_bytes(raw_key: &[u8]) -> Self {
683 Blake2bKey {
684 key: HMACKey::from_bytes(raw_key),
685 key_id: None,
686 }
687 }
688
689 pub fn to_bytes(&self) -> Vec<u8> {
690 self.key.to_bytes()
691 }
692
693 pub fn generate() -> Self {
694 Blake2bKey {
695 key: HMACKey::generate(),
696 key_id: None,
697 }
698 }
699
700 #[cfg(feature = "cwt")]
719 pub fn verify_cwt_token_with_custom_claims<CustomClaims>(
720 &self,
721 token: impl AsRef<[u8]>,
722 options: Option<VerificationOptions>,
723 ) -> Result<JWTClaims<CustomClaims>, Error>
724 where
725 CustomClaims: DeserializeOwned + Default,
726 {
727 <Self as MACLike>::verify_cwt_token_with_custom_claims::<CustomClaims>(self, token, options)
728 }
729
730 pub fn generate_with_salt() -> Self {
731 Blake2bKey {
732 key: HMACKey::generate_with_salt(),
733 key_id: None,
734 }
735 }
736
737 pub fn with_key_id(mut self, key_id: &str) -> Self {
738 self.key_id = Some(key_id.to_string());
739 self
740 }
741}