jwt_next/algorithm/
rust_crypto.rs1use base64::Engine;
6use digest::{
7 block_buffer::Eager,
8 consts::U256,
9 core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore},
10 generic_array::typenum::{IsLess, Le, NonZero},
11 HashMarker,
12};
13use hmac::{Hmac, Mac};
14
15use crate::algorithm::{AlgorithmType, SigningAlgorithm, VerifyingAlgorithm};
16use crate::error::Error;
17use crate::SEPARATOR;
18
19pub mod asymmetric;
20
21pub trait TypeLevelAlgorithmType {
26 fn algorithm_type() -> AlgorithmType;
27}
28
29macro_rules! type_level_algorithm_type {
30 ($rust_crypto_type: ty, $algorithm_type: expr) => {
31 impl TypeLevelAlgorithmType for $rust_crypto_type {
32 fn algorithm_type() -> AlgorithmType {
33 $algorithm_type
34 }
35 }
36 };
37}
38
39type_level_algorithm_type!(sha2::Sha256, AlgorithmType::Hs256);
40type_level_algorithm_type!(sha2::Sha384, AlgorithmType::Hs384);
41type_level_algorithm_type!(sha2::Sha512, AlgorithmType::Hs512);
42
43impl<D> SigningAlgorithm for Hmac<D>
44where
45 D: CoreProxy + TypeLevelAlgorithmType,
46 D::Core: HashMarker
47 + BufferKindUser<BufferKind = Eager>
48 + FixedOutputCore
49 + digest::Reset
50 + Default
51 + Clone,
52 <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
53 Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
54{
55 fn algorithm_type(&self) -> AlgorithmType {
56 D::algorithm_type()
57 }
58
59 fn sign(&self, header: &str, claims: &str) -> Result<String, Error> {
60 let hmac = get_hmac_with_data(self, header, claims);
61 let mac_result = hmac.finalize();
62 let code = mac_result.into_bytes();
63 Ok(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(code))
64 }
65}
66
67impl<D> VerifyingAlgorithm for Hmac<D>
68where
69 D: CoreProxy + TypeLevelAlgorithmType,
70 D::Core: HashMarker
71 + BufferKindUser<BufferKind = Eager>
72 + FixedOutputCore
73 + digest::Reset
74 + Default
75 + Clone,
76 <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
77 Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
78{
79 fn algorithm_type(&self) -> AlgorithmType {
80 D::algorithm_type()
81 }
82
83 fn verify_bytes(&self, header: &str, claims: &str, signature: &[u8]) -> Result<bool, Error> {
84 let hmac = get_hmac_with_data(self, header, claims);
85 hmac.verify_slice(signature)?;
86 Ok(true)
87 }
88}
89
90fn get_hmac_with_data<D>(hmac: &Hmac<D>, header: &str, claims: &str) -> Hmac<D>
91where
92 D: CoreProxy,
93 D::Core: HashMarker
94 + BufferKindUser<BufferKind = Eager>
95 + FixedOutputCore
96 + digest::Reset
97 + Default
98 + Clone,
99 <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
100 Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
101{
102 let mut hmac = hmac.clone();
103 hmac.reset();
104 hmac.update(header.as_bytes());
105 hmac.update(SEPARATOR.as_bytes());
106 hmac.update(claims.as_bytes());
107 hmac
108}
109
110#[cfg(test)]
111mod tests {
112 use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
113 use crate::error::Error;
114 use hmac::{Hmac, Mac};
115 use sha2::Sha256;
116
117 #[test]
118 pub fn sign() -> Result<(), Error> {
119 let header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
120 let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
121 let expected_signature = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
122
123 let signer: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
124 let computed_signature = SigningAlgorithm::sign(&signer, header, claims)?;
125
126 assert_eq!(computed_signature, expected_signature);
127 Ok(())
128 }
129
130 #[test]
131 pub fn verify() -> Result<(), Error> {
132 let header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
133 let claims = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9";
134 let signature = "TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
135
136 let verifier: Hmac<Sha256> = Hmac::new_from_slice(b"secret")?;
137 assert!(VerifyingAlgorithm::verify(
138 &verifier, header, claims, signature
139 )?);
140 Ok(())
141 }
142}