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