Skip to main content

jwt/
jwt_crypto.rs

1use alloc::vec::Vec;
2
3use constant_time_eq::constant_time_eq;
4use crypto::{
5    Hasher,
6    blake3::Blake3,
7    curve25519::ed25519,
8    hmac::Hmac,
9    p256, rsa,
10    sha2::{Sha256, Sha384, Sha512},
11};
12use smallvec::SmallVec;
13
14use crate::{Algorithm, Error};
15
16pub(crate) const SIGNATURE_MAX_SIZE: usize = 3309; // ML-DSA-65
17
18pub trait Signer {
19    fn sign(&self, message: &[u8]) -> Result<Signature, Error>;
20    fn algorithm(&self) -> Algorithm;
21}
22
23pub trait Verifier {
24    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error>;
25    fn algorithm(&self) -> Algorithm;
26}
27
28////////////////////////////////////////////////////////////////////////////////////////////////////
29// Signature
30////////////////////////////////////////////////////////////////////////////////////////////////////
31
32#[derive(Clone, Copy)]
33pub struct Signature {
34    value: [u8; SIGNATURE_MAX_SIZE],
35    length: usize,
36}
37
38impl core::ops::Deref for Signature {
39    type Target = [u8];
40
41    #[inline]
42    fn deref(&self) -> &[u8] {
43        &self.value[..self.length as usize]
44    }
45}
46
47impl AsRef<[u8]> for Signature {
48    #[inline]
49    fn as_ref(&self) -> &[u8] {
50        &self.value[..self.length]
51    }
52}
53
54impl TryFrom<&[u8]> for Signature {
55    type Error = Error;
56
57    #[inline]
58    fn try_from(signature: &[u8]) -> Result<Self, Self::Error> {
59        let length = signature.len();
60        if length > SIGNATURE_MAX_SIZE {
61            return Err(Error::InvalidSignature);
62        }
63
64        let mut value = [0u8; SIGNATURE_MAX_SIZE];
65        value[..length].copy_from_slice(signature);
66
67        return Ok(Signature {
68            value,
69            length,
70        });
71    }
72}
73
74impl<const N: usize> TryFrom<[u8; N]> for Signature {
75    type Error = Error;
76
77    #[inline]
78    fn try_from(signature: [u8; N]) -> Result<Self, Self::Error> {
79        signature.as_slice().try_into()
80    }
81}
82
83impl<const N: usize> TryFrom<&[u8; N]> for Signature {
84    type Error = Error;
85
86    #[inline]
87    fn try_from(signature: &[u8; N]) -> Result<Self, Self::Error> {
88        signature.as_slice().try_into()
89    }
90}
91
92impl TryFrom<Vec<u8>> for Signature {
93    type Error = Error;
94
95    #[inline]
96    fn try_from(signature: Vec<u8>) -> Result<Self, Self::Error> {
97        signature.as_slice().try_into()
98    }
99}
100
101////////////////////////////////////////////////////////////////////////////////////////////////////
102// BLAKE3
103////////////////////////////////////////////////////////////////////////////////////////////////////
104
105/// A `BLAKE3` key.
106#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
107pub struct Blake3Key {
108    key: [u8; 32],
109}
110
111impl Blake3Key {
112    /// Generates a random 256-bit [`Blake3Key`].
113    pub fn generate() -> Blake3Key {
114        let key = crypto::random_bytes();
115        return Blake3Key {
116            key,
117        };
118    }
119
120    #[inline(always)]
121    pub fn from_bytes(key: &[u8; 32]) -> Blake3Key {
122        return Blake3Key {
123            key: *key,
124        };
125    }
126
127    #[inline(always)]
128    pub fn as_bytes(&self) -> &[u8; 32] {
129        return &self.key;
130    }
131}
132
133impl Signer for Blake3Key {
134    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
135        let signature = Blake3::keyed_hash(&self.key, message);
136        return signature.as_ref().try_into();
137    }
138
139    #[inline(always)]
140    fn algorithm(&self) -> Algorithm {
141        Algorithm::BLAKE3
142    }
143}
144
145impl Verifier for Blake3Key {
146    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
147        let expected_signature = Blake3::keyed_hash(&self.key, message);
148        return match constant_time_eq(signature.as_ref(), &expected_signature) {
149            true => Ok(()),
150            false => Err(Error::InvalidSignature),
151        };
152    }
153
154    #[inline(always)]
155    fn algorithm(&self) -> Algorithm {
156        Algorithm::BLAKE3
157    }
158}
159
160////////////////////////////////////////////////////////////////////////////////////////////////////
161// HMAC-SHA-256
162////////////////////////////////////////////////////////////////////////////////////////////////////
163
164/// A `HS256` key.
165#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
166pub struct HmacSha256Key {
167    key: SmallVec<u8, 32>,
168}
169
170impl HmacSha256Key {
171    /// Generates a random 256-bit [`HmacSha256Key`].
172    pub fn generate() -> HmacSha256Key {
173        let key: [u8; 32] = crypto::random_bytes();
174        return HmacSha256Key {
175            key: key.into(),
176        };
177    }
178
179    /// Creates a new [`HmacSha256Key`] from bytes. Returns an error is the key is shorter than
180    /// 16 bytes (128 bits).
181    pub fn from_bytes(key: &[u8]) -> Result<HmacSha256Key, Error> {
182        // require at least a 128-bit key
183        if key.len() < 16 {
184            return Err(Error::InvalidKey);
185        }
186
187        return Ok(HmacSha256Key {
188            key: SmallVec::from_slice_copy(key),
189        });
190    }
191
192    #[inline(always)]
193    pub fn as_bytes(&self) -> &[u8] {
194        return &self.key;
195    }
196}
197
198impl Signer for HmacSha256Key {
199    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
200        let signature = Hmac::<Sha256>::mac(&self.key, message);
201        return signature.as_ref().try_into();
202    }
203
204    #[inline(always)]
205    fn algorithm(&self) -> Algorithm {
206        Algorithm::HS256
207    }
208}
209
210impl Verifier for HmacSha256Key {
211    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
212        let message_mac = Hmac::<Sha256>::mac(&self.key, message);
213        return match constant_time_eq(&message_mac, signature) {
214            true => Ok(()),
215            false => Err(Error::InvalidSignature),
216        };
217    }
218
219    #[inline(always)]
220    fn algorithm(&self) -> Algorithm {
221        Algorithm::HS256
222    }
223}
224
225////////////////////////////////////////////////////////////////////////////////////////////////////
226// HMAC-SHA-512
227////////////////////////////////////////////////////////////////////////////////////////////////////
228
229/// A `HS512` key.
230#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
231pub struct HmacSha512Key {
232    key: SmallVec<u8, 32>,
233}
234
235impl HmacSha512Key {
236    /// Generates a random 256-bit [`HmacSha512Key`].
237    pub fn generate() -> HmacSha256Key {
238        let key: [u8; 32] = crypto::random_bytes();
239        return HmacSha256Key {
240            key: key.into(),
241        };
242    }
243
244    /// Creates a new [`HmacSha512Key`] from bytes. Returns an error is the key is shorter than
245    /// 16 bytes (128 bits).
246    pub fn from_bytes(key: &[u8]) -> Result<HmacSha512Key, Error> {
247        // require at least a 128-bit key
248        if key.len() < 16 {
249            return Err(Error::InvalidKey);
250        }
251
252        return Ok(HmacSha512Key {
253            key: SmallVec::from_slice_copy(key),
254        });
255    }
256
257    #[inline(always)]
258    pub fn as_bytes(&self) -> &[u8] {
259        return &self.key;
260    }
261}
262
263impl Signer for HmacSha512Key {
264    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
265        let signature = Hmac::<Sha512>::mac(&self.key, message);
266        return signature.as_ref().try_into();
267    }
268
269    #[inline(always)]
270    fn algorithm(&self) -> Algorithm {
271        Algorithm::HS512
272    }
273}
274
275impl Verifier for HmacSha512Key {
276    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
277        let message_mac = Hmac::<Sha512>::mac(&self.key, message);
278        return match constant_time_eq(&message_mac, signature) {
279            true => Ok(()),
280            false => Err(Error::InvalidSignature),
281        };
282    }
283
284    #[inline(always)]
285    fn algorithm(&self) -> Algorithm {
286        Algorithm::HS512
287    }
288}
289
290////////////////////////////////////////////////////////////////////////////////////////////////////
291// Ed25519
292////////////////////////////////////////////////////////////////////////////////////////////////////
293
294// TODO: zeroize?
295pub struct Ed25519SecretKey {
296    pub(crate) key: ed25519::SecretKey,
297}
298
299impl Ed25519SecretKey {
300    /// Generates a random [`Ed25519SecretKey`].
301    pub fn generate() -> Ed25519SecretKey {
302        let key = ed25519::SecretKey::generate();
303        return Ed25519SecretKey {
304            key,
305        };
306    }
307
308    /// Imports the private key from a seed.
309    pub fn from_bytes(seed: &[u8; 32]) -> Result<Ed25519SecretKey, Error> {
310        let key = ed25519::SecretKey::from_bytes(seed);
311        return Ok(Ed25519SecretKey {
312            key,
313        });
314    }
315
316    /// Converts the private key to a byte array.
317    #[inline(always)]
318    pub(crate) fn to_bytes(&self) -> [u8; 32] {
319        return self.key.to_bytes();
320    }
321
322    #[inline(always)]
323    pub fn public_key(&self) -> Ed25519PublicKey {
324        return Ed25519PublicKey {
325            key: self.key.public_key(),
326        };
327    }
328}
329
330impl From<ed25519::SecretKey> for Ed25519SecretKey {
331    fn from(key: ed25519::SecretKey) -> Self {
332        Self {
333            key,
334        }
335    }
336}
337
338impl Signer for Ed25519SecretKey {
339    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
340        return self.key.sign(message).as_ref().try_into();
341    }
342
343    #[inline(always)]
344    fn algorithm(&self) -> Algorithm {
345        Algorithm::EdDSA
346    }
347}
348
349pub struct Ed25519PublicKey {
350    key: ed25519::PublicKey,
351}
352
353impl Ed25519PublicKey {
354    pub fn from_bytes(public_key: &[u8; 32]) -> Result<Ed25519PublicKey, Error> {
355        let key = ed25519::PublicKey::from_bytes(public_key).map_err(|_| Error::InvalidKey)?;
356        Ok(Ed25519PublicKey {
357            key,
358        })
359    }
360
361    /// Converts the public key to a byte array.
362    #[inline(always)]
363    pub fn to_bytes(&self) -> [u8; 32] {
364        self.key.to_bytes()
365    }
366}
367
368impl From<ed25519::PublicKey> for Ed25519PublicKey {
369    fn from(key: ed25519::PublicKey) -> Self {
370        Self {
371            key,
372        }
373    }
374}
375
376impl Verifier for Ed25519PublicKey {
377    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
378        let signature = signature.try_into().map_err(|_| Error::InvalidSignature)?;
379        return self
380            .key
381            .verify(message, &signature)
382            .map_err(|_| Error::InvalidSignature);
383    }
384
385    #[inline(always)]
386    fn algorithm(&self) -> Algorithm {
387        Algorithm::EdDSA
388    }
389}
390
391////////////////////////////////////////////////////////////////////////////////////////////////////
392// P-256
393////////////////////////////////////////////////////////////////////////////////////////////////////
394
395// TODO: zeroize
396pub struct P256SecretKey {
397    key: p256::SecretKey,
398}
399
400impl P256SecretKey {
401    /// Generates a random [`P256SecretKey`].
402    pub fn generate() -> Result<P256SecretKey, Error> {
403        let key = p256::SecretKey::generate().map_err(|_| Error::InvalidKey)?;
404        return Ok(P256SecretKey {
405            key,
406        });
407    }
408
409    #[inline(always)]
410    pub fn from_bytes(bytes: &[u8; 32]) -> Result<P256SecretKey, Error> {
411        let key = p256::SecretKey::from_bytes(bytes).map_err(|_| Error::InvalidKey)?;
412        return Ok(P256SecretKey {
413            key,
414        });
415    }
416
417    /// Converts the secret key to byte array.
418    #[inline(always)]
419    pub(crate) fn to_bytes(&self) -> [u8; 32] {
420        return self.key.to_bytes();
421    }
422
423    #[inline(always)]
424    pub fn public_key(&self) -> P256PublicKey {
425        return P256PublicKey {
426            key: self.key.public_key(),
427        };
428    }
429}
430
431impl From<p256::SecretKey> for P256SecretKey {
432    fn from(key: p256::SecretKey) -> Self {
433        Self {
434            key,
435        }
436    }
437}
438
439impl Signer for P256SecretKey {
440    fn sign(&self, message: &[u8]) -> Result<Signature, Error> {
441        return self
442            .key
443            .sign(message)
444            .map_err(|err| Error::Unspecified(alloc::format!("error signing message: {err:?}")))?
445            .as_ref()
446            .try_into();
447    }
448
449    #[inline(always)]
450    fn algorithm(&self) -> Algorithm {
451        Algorithm::ES256
452    }
453}
454
455pub struct P256PublicKey {
456    pub(crate) key: p256::PublicKey,
457}
458
459impl P256PublicKey {
460    pub fn from_x_y(x: &[u8; 32], y: &[u8; 32]) -> Result<P256PublicKey, Error> {
461        let key = p256::PublicKey::from_x_y(x, y).map_err(|_| Error::InvalidKey)?;
462        Ok(P256PublicKey {
463            key,
464        })
465    }
466
467    pub fn from_bytes(public_key: &[u8]) -> Result<P256PublicKey, Error> {
468        let key = p256::PublicKey::from_bytes(public_key).map_err(|_| Error::InvalidKey)?;
469        Ok(P256PublicKey {
470            key,
471        })
472    }
473
474    // Converts the public key to a byte array.
475    // #[inline(always)]
476    // pub(crate) fn to_bytes(&self) -> [u8; 65] {
477    //     self.key.to_bytes()
478    // }
479}
480
481impl From<p256::PublicKey> for P256PublicKey {
482    fn from(key: p256::PublicKey) -> Self {
483        Self {
484            key,
485        }
486    }
487}
488
489impl Verifier for P256PublicKey {
490    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
491        let signature = signature.try_into().map_err(|_| Error::InvalidSignature)?;
492        return self
493            .key
494            .verify(message, &signature)
495            .map_err(|_| Error::InvalidSignature);
496    }
497
498    #[inline(always)]
499    fn algorithm(&self) -> Algorithm {
500        Algorithm::ES256
501    }
502}
503
504////////////////////////////////////////////////////////////////////////////////////////////////////
505// RSA
506////////////////////////////////////////////////////////////////////////////////////////////////////
507
508/// An RSA public key for JWT verification, supporting both PKCS#1 v1.5 and RSA-PSS signatures.
509///
510/// # Algorithms
511///
512/// | Variant   | JWT Algorithm | Scheme          | Hash     |
513/// |-----------|---------------|-----------------|----------|
514/// | RS256     | `RS256`       | PKCS#1 v1.5     | SHA-256  |
515/// | RS384     | `RS384`       | PKCS#1 v1.5     | SHA-384  |
516/// | RS512     | `RS512`       | PKCS#1 v1.5     | SHA-512  |
517/// | PS256     | `PS256`       | RSA-PSS         | SHA-256  |
518/// | PS384     | `PS384`       | RSA-PSS         | SHA-384  |
519/// | PS512     | `PS512`       | RSA-PSS         | SHA-512  |
520///
521/// Signing is not supported — this key type is verification-only.
522///
523/// # Constructors
524///
525/// * [`RsaPublicKey::from_n_e`] — build from raw modulus and exponent bytes (useful with JWK)
526/// * [`RsaPublicKey::from_pkcs1_der`] — parse from PKCS#1 DER `SEQUENCE { INTEGER n, INTEGER e }`
527///
528/// # Errors
529///
530/// Returns [`Error::InvalidKey`] if the algorithm is not an RSA variant or
531/// if the underlying RSA key parsing fails. Returns [`Error::InvalidSignature`]
532/// on verification failures.
533pub struct RsaPublicKey {
534    pub(crate) key: rsa::PublicKey,
535    pub(crate) alg: Algorithm,
536}
537
538impl RsaPublicKey {
539    /// Build an RSA public key from raw modulus `n` and public exponent `e`
540    /// (both big-endian byte slices).
541    ///
542    /// This is useful when importing keys from JWK format where `n` and `e`
543    /// are base64url-encoded big-endian byte values.
544    ///
545    /// # Errors
546    ///
547    /// Returns [`Error::InvalidKey`] if `alg` is not an RSA algorithm
548    /// or if the modulus/exponent bytes describe an invalid RSA key.
549    pub(crate) fn from_n_e(alg: Algorithm, n: &[u8], e: &[u8]) -> Result<Self, Error> {
550        if !matches!(
551            alg,
552            Algorithm::RS256
553                | Algorithm::RS384
554                | Algorithm::RS512
555                | Algorithm::PS256
556                | Algorithm::PS384
557                | Algorithm::PS512
558        ) {
559            return Err(Error::InvalidKey);
560        }
561        let key = rsa::PublicKey::from_n_e(n, e).map_err(|_| Error::InvalidKey)?;
562        Ok(RsaPublicKey {
563            key,
564            alg,
565        })
566    }
567
568    /// Parse an RSA public key from PKCS#1 DER bytes.
569    ///
570    /// The input is the raw `SEQUENCE { INTEGER n, INTEGER e }` inside the
571    /// `SubjectPublicKeyInfo` BIT STRING.
572    ///
573    /// # Errors
574    ///
575    /// Returns [`Error::InvalidKey`] if `alg` is not an RSA algorithm
576    /// or if the DER bytes do not encode a valid RSA public key.
577    pub fn from_pkcs1_der(pkcs1_der: &[u8], alg: Algorithm) -> Result<Self, Error> {
578        if !matches!(
579            alg,
580            Algorithm::RS256
581                | Algorithm::RS384
582                | Algorithm::RS512
583                | Algorithm::PS256
584                | Algorithm::PS384
585                | Algorithm::PS512
586        ) {
587            return Err(Error::InvalidKey);
588        }
589        let key = rsa::PublicKey::from_pkcs1_der(pkcs1_der).map_err(|_| Error::InvalidKey)?;
590        Ok(RsaPublicKey {
591            key,
592            alg,
593        })
594    }
595}
596
597impl Verifier for RsaPublicKey {
598    fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Error> {
599        match self.alg {
600            Algorithm::RS256 => {
601                let digest = Sha256::hash(message);
602                self.key
603                    .verify_pkcs1_v1_5(signature, digest.as_ref(), rsa::DIGEST_INFO_SHA256_PREFIX)
604            }
605            Algorithm::RS384 => {
606                let digest = Sha384::hash(message);
607                self.key
608                    .verify_pkcs1_v1_5(signature, digest.as_ref(), rsa::DIGEST_INFO_SHA384_PREFIX)
609            }
610            Algorithm::RS512 => {
611                let digest = Sha512::hash(message);
612                self.key
613                    .verify_pkcs1_v1_5(signature, digest.as_ref(), rsa::DIGEST_INFO_SHA512_PREFIX)
614            }
615            Algorithm::PS256 => self.key.verify_pss::<Sha256>(signature, message, Sha256::OUTPUT_SIZE),
616            Algorithm::PS384 => self.key.verify_pss::<Sha384>(signature, message, Sha384::OUTPUT_SIZE),
617            Algorithm::PS512 => self.key.verify_pss::<Sha512>(signature, message, Sha512::OUTPUT_SIZE),
618            _ => return Err(Error::InvalidKey),
619        }
620        .map_err(|_| Error::InvalidSignature)
621    }
622
623    #[inline(always)]
624    fn algorithm(&self) -> Algorithm {
625        self.alg
626    }
627}