jwt_simple/algorithms/
hmac.rs1use 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 {
30 HMACKey {
31 raw_key: raw_key.to_vec(),
32 metadata: None,
33 }
34 }
35
36 pub fn to_bytes(&self) -> Vec<u8> {
37 self.raw_key.clone()
38 }
39
40 pub fn generate() -> Self {
41 let mut raw_key = vec![0u8; 32];
42 rand::thread_rng().fill_bytes(&mut raw_key);
43 HMACKey {
44 raw_key,
45 metadata: None,
46 }
47 }
48}
49
50impl AsRef<[u8]> for HMACKey {
51 fn as_ref(&self) -> &[u8] {
52 &self.raw_key
53 }
54}
55
56pub trait MACLike {
57 fn jwt_alg_name() -> &'static str;
58 fn key(&self) -> &HMACKey;
59 fn key_id(&self) -> &Option<String>;
60 fn set_key_id(&mut self, key_id: String);
61 fn metadata(&self) -> &Option<KeyMetadata>;
62 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error>;
63 fn authentication_tag(&self, authenticated: &str) -> Vec<u8>;
64
65 fn authenticate<CustomClaims: Serialize + DeserializeOwned>(
66 &self,
67 claims: JWTClaims<CustomClaims>,
68 ) -> Result<String, Error> {
69 let jwt_header = JWTHeader::new(Self::jwt_alg_name().to_string(), self.key_id().clone())
70 .with_metadata(self.metadata());
71 Token::build(&jwt_header, claims, |authenticated| {
72 Ok(self.authentication_tag(authenticated))
73 })
74 }
75
76 fn verify_token<CustomClaims: Serialize + DeserializeOwned>(
77 &self,
78 token: &str,
79 options: Option<VerificationOptions>,
80 ) -> Result<JWTClaims<CustomClaims>, Error> {
81 Token::verify(
82 Self::jwt_alg_name(),
83 token,
84 options,
85 |authenticated, authentication_tag| {
86 ensure!(
87 timingsafe_eq(&self.authentication_tag(authenticated), authentication_tag),
88 JWTError::InvalidAuthenticationTag
89 );
90 Ok(())
91 },
92 )
93 }
94
95 #[cfg(feature = "cwt")]
96 fn verify_cwt_token(
97 &self,
98 token: impl AsRef<[u8]>,
99 options: Option<VerificationOptions>,
100 ) -> Result<JWTClaims<NoCustomClaims>, Error> {
101 CWTToken::verify(
102 Self::jwt_alg_name(),
103 token,
104 options,
105 |authenticated, authentication_tag| {
106 ensure!(
107 timingsafe_eq(&self.authentication_tag(authenticated), authentication_tag),
108 JWTError::InvalidAuthenticationTag
109 );
110 Ok(())
111 },
112 )
113 }
114
115 fn create_key_id(&mut self) -> &str {
116 self.set_key_id(
117 Base64UrlSafeNoPadding::encode_to_string(hmac_sha256::Hash::hash(
118 &self.key().to_bytes(),
119 ))
120 .unwrap(),
121 );
122 self.key_id().as_ref().map(|x| x.as_str()).unwrap()
123 }
124}
125
126#[derive(Debug, Clone)]
127pub struct HS256Key {
128 key: HMACKey,
129 key_id: Option<String>,
130}
131
132impl MACLike for HS256Key {
133 fn jwt_alg_name() -> &'static str {
134 "HS256"
135 }
136
137 fn key(&self) -> &HMACKey {
138 &self.key
139 }
140
141 fn key_id(&self) -> &Option<String> {
142 &self.key_id
143 }
144
145 fn set_key_id(&mut self, key_id: String) {
146 self.key_id = Some(key_id);
147 }
148
149 fn metadata(&self) -> &Option<KeyMetadata> {
150 &self.key.metadata
151 }
152
153 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
154 self.key.metadata = Some(metadata);
155 Ok(())
156 }
157
158 fn authentication_tag(&self, authenticated: &str) -> Vec<u8> {
159 hmac_sha256::HMAC::mac(authenticated.as_bytes(), self.key().as_ref()).to_vec()
160 }
161}
162
163impl HS256Key {
164 pub fn from_bytes(raw_key: &[u8]) -> Self {
165 HS256Key {
166 key: HMACKey::from_bytes(raw_key),
167 key_id: None,
168 }
169 }
170
171 pub fn to_bytes(&self) -> Vec<u8> {
172 self.key.to_bytes()
173 }
174
175 pub fn generate() -> Self {
176 HS256Key {
177 key: HMACKey::generate(),
178 key_id: None,
179 }
180 }
181
182 pub fn with_key_id(mut self, key_id: &str) -> Self {
183 self.key_id = Some(key_id.to_string());
184 self
185 }
186}
187
188#[derive(Debug, Clone)]
189pub struct HS512Key {
190 key: HMACKey,
191 key_id: Option<String>,
192}
193
194impl MACLike for HS512Key {
195 fn jwt_alg_name() -> &'static str {
196 "HS512"
197 }
198
199 fn key(&self) -> &HMACKey {
200 &self.key
201 }
202
203 fn key_id(&self) -> &Option<String> {
204 &self.key_id
205 }
206
207 fn set_key_id(&mut self, key_id: String) {
208 self.key_id = Some(key_id);
209 }
210
211 fn metadata(&self) -> &Option<KeyMetadata> {
212 &self.key.metadata
213 }
214
215 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
216 self.key.metadata = Some(metadata);
217 Ok(())
218 }
219
220 fn authentication_tag(&self, authenticated: &str) -> Vec<u8> {
221 hmac_sha512::HMAC::mac(authenticated.as_bytes(), self.key().as_ref()).to_vec()
222 }
223}
224
225impl HS512Key {
226 pub fn from_bytes(raw_key: &[u8]) -> Self {
227 HS512Key {
228 key: HMACKey::from_bytes(raw_key),
229 key_id: None,
230 }
231 }
232
233 pub fn to_bytes(&self) -> Vec<u8> {
234 self.key.to_bytes()
235 }
236
237 pub fn generate() -> Self {
238 HS512Key {
239 key: HMACKey::generate(),
240 key_id: None,
241 }
242 }
243
244 pub fn with_key_id(mut self, key_id: &str) -> Self {
245 self.key_id = Some(key_id.to_string());
246 self
247 }
248}
249
250#[derive(Debug, Clone)]
251pub struct HS384Key {
252 key: HMACKey,
253 key_id: Option<String>,
254}
255
256impl MACLike for HS384Key {
257 fn jwt_alg_name() -> &'static str {
258 "HS384"
259 }
260
261 fn key(&self) -> &HMACKey {
262 &self.key
263 }
264
265 fn key_id(&self) -> &Option<String> {
266 &self.key_id
267 }
268
269 fn set_key_id(&mut self, key_id: String) {
270 self.key_id = Some(key_id);
271 }
272
273 fn metadata(&self) -> &Option<KeyMetadata> {
274 &self.key.metadata
275 }
276
277 fn attach_metadata(&mut self, metadata: KeyMetadata) -> Result<(), Error> {
278 self.key.metadata = Some(metadata);
279 Ok(())
280 }
281
282 fn authentication_tag(&self, authenticated: &str) -> Vec<u8> {
283 hmac_sha384::HMAC::mac(authenticated.as_bytes(), self.key().as_ref()).to_vec()
284 }
285}
286
287impl HS384Key {
288 pub fn from_bytes(raw_key: &[u8]) -> Self {
289 HS384Key {
290 key: HMACKey::from_bytes(raw_key),
291 key_id: None,
292 }
293 }
294
295 pub fn to_bytes(&self) -> Vec<u8> {
296 self.key.to_bytes()
297 }
298
299 pub fn generate() -> Self {
300 HS384Key {
301 key: HMACKey::generate(),
302 key_id: None,
303 }
304 }
305
306 pub fn with_key_id(mut self, key_id: &str) -> Self {
307 self.key_id = Some(key_id.to_string());
308 self
309 }
310}