jsonwebtoken/crypto/
mod.rs

1use ring::constant_time::verify_slices_are_equal;
2use ring::{hmac, signature};
3
4use crate::algorithms::Algorithm;
5use crate::decoding::{DecodingKey, DecodingKeyKind};
6use crate::encoding::EncodingKey;
7use crate::errors::Result;
8use crate::serialization::{b64_decode, b64_encode};
9
10pub(crate) mod ecdsa;
11pub(crate) mod eddsa;
12pub(crate) mod rsa;
13
14/// The actual HS signing + encoding
15/// Could be in its own file to match RSA/EC but it's 2 lines...
16pub(crate) fn sign_hmac(alg: hmac::Algorithm, key: &[u8], message: &[u8]) -> String {
17    let digest = hmac::sign(&hmac::Key::new(alg, key), message);
18    b64_encode(digest)
19}
20
21/// Take the payload of a JWT, sign it using the algorithm given and return
22/// the base64 url safe encoded of the result.
23///
24/// If you just want to encode a JWT, use `encode` instead.
25pub fn sign(message: &[u8], key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
26    match algorithm {
27        Algorithm::HS256 => Ok(sign_hmac(hmac::HMAC_SHA256, key.inner(), message)),
28        Algorithm::HS384 => Ok(sign_hmac(hmac::HMAC_SHA384, key.inner(), message)),
29        Algorithm::HS512 => Ok(sign_hmac(hmac::HMAC_SHA512, key.inner(), message)),
30
31        Algorithm::ES256 | Algorithm::ES384 => {
32            ecdsa::sign(ecdsa::alg_to_ec_signing(algorithm), key.inner(), message)
33        }
34
35        Algorithm::EdDSA => eddsa::sign(key.inner(), message),
36
37        Algorithm::RS256
38        | Algorithm::RS384
39        | Algorithm::RS512
40        | Algorithm::PS256
41        | Algorithm::PS384
42        | Algorithm::PS512 => rsa::sign(rsa::alg_to_rsa_signing(algorithm), key.inner(), message),
43    }
44}
45
46/// See Ring docs for more details
47fn verify_ring(
48    alg: &'static dyn signature::VerificationAlgorithm,
49    signature: &str,
50    message: &[u8],
51    key: &[u8],
52) -> Result<bool> {
53    let signature_bytes = b64_decode(signature)?;
54    let public_key = signature::UnparsedPublicKey::new(alg, key);
55    let res = public_key.verify(message, &signature_bytes);
56
57    Ok(res.is_ok())
58}
59
60/// Compares the signature given with a re-computed signature for HMAC or using the public key
61/// for RSA/EC.
62///
63/// If you just want to decode a JWT, use `decode` instead.
64///
65/// `signature` is the signature part of a jwt (text after the second '.')
66///
67/// `message` is base64(header) + "." + base64(claims)
68pub fn verify(
69    signature: &str,
70    message: &[u8],
71    key: &DecodingKey,
72    algorithm: Algorithm,
73) -> Result<bool> {
74    match algorithm {
75        Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => {
76            // we just re-sign the message with the key and compare if they are equal
77            let signed = sign(message, &EncodingKey::from_secret(key.as_bytes()), algorithm)?;
78            Ok(verify_slices_are_equal(signature.as_ref(), signed.as_ref()).is_ok())
79        }
80        Algorithm::ES256 | Algorithm::ES384 => verify_ring(
81            ecdsa::alg_to_ec_verification(algorithm),
82            signature,
83            message,
84            key.as_bytes(),
85        ),
86        Algorithm::EdDSA => verify_ring(
87            eddsa::alg_to_ec_verification(algorithm),
88            signature,
89            message,
90            key.as_bytes(),
91        ),
92        Algorithm::RS256
93        | Algorithm::RS384
94        | Algorithm::RS512
95        | Algorithm::PS256
96        | Algorithm::PS384
97        | Algorithm::PS512 => {
98            let alg = rsa::alg_to_rsa_parameters(algorithm);
99            match &key.kind {
100                DecodingKeyKind::SecretOrDer(bytes) => verify_ring(alg, signature, message, bytes),
101                DecodingKeyKind::RsaModulusExponent { n, e } => {
102                    rsa::verify_from_components(alg, signature, message, (n, e))
103                }
104            }
105        }
106    }
107}