jsonwebtoken_rustcrypto/crypto/
mod.rs

1use hmac::{Hmac, Mac};
2
3use crate::algorithms::Algorithm;
4use crate::decoding::DecodingKey;
5use crate::encoding::EncodingKey;
6use crate::errors::{new_error, ErrorKind, Result};
7use crate::serialization::{b64_decode, b64_encode};
8
9use sha2::{Sha256, Sha384, Sha512};
10// pub(crate) mod ecdsa;
11pub(crate) mod rsa;
12
13type HmacSha256 = Hmac<Sha256>;
14type HmacSha384 = Hmac<Sha384>;
15type HmacSha512 = Hmac<Sha512>;
16/// The actual HS signing + encoding
17/// Could be in its own file to match RSA/EC but it's 2 lines...
18pub(crate) fn sign_hmac(alg: Algorithm, key: &[u8], message: &str) -> Result<String> {
19    // println!("alg: {:?}\nkey: {:?}\nmessage: {:?}");
20
21    // let digest = hmac::sign(&hmac::Key::new(alg, key), message.as_bytes());
22    let digest = match alg {
23        Algorithm::HS256 => {
24            let mut mac = HmacSha256::new_from_slice(key).unwrap();
25            mac.update(message.as_bytes());
26            b64_encode(mac.finalize().into_bytes().as_slice())
27        }
28        Algorithm::HS384 => {
29            let mut mac = HmacSha384::new_from_slice(key).unwrap();
30            mac.update(message.as_bytes());
31            b64_encode(mac.finalize().into_bytes().as_slice())
32        }
33        Algorithm::HS512 => {
34            let mut mac = HmacSha512::new_from_slice(key).unwrap();
35            mac.update(message.as_bytes());
36            b64_encode(mac.finalize().into_bytes().as_slice())
37        }
38        _ => unreachable!(),
39    };
40    Ok(digest)
41}
42
43/// Validates that the key can be used with the given algorithm
44pub fn validate_matching_key(key: &EncodingKey, algorithm: Algorithm) -> Result<()> {
45    match key {
46        EncodingKey::Hmac(_) => match algorithm {
47            Algorithm::HS256 => Ok(()),
48            Algorithm::HS384 => Ok(()),
49            Algorithm::HS512 => Ok(()),
50            _ => Err(ErrorKind::InvalidAlgorithm.into()),
51        },
52        EncodingKey::Rsa(_) => match algorithm {
53            Algorithm::RS256
54            | Algorithm::PS256
55            | Algorithm::PS384
56            | Algorithm::PS512
57            | Algorithm::RS384
58            | Algorithm::RS512 => Ok(()),
59            _ => Err(ErrorKind::InvalidAlgorithm.into()),
60        },
61        // EncodingKey::EcPkcs8(_)
62        //     => match algorithm {
63        //         Algorithm::ES256 | Algorithm::ES384 => Ok(()),
64        //         _ => Err(ErrorKind::InvalidAlgorithm.into())
65        //     }
66    }
67}
68
69/// Take the payload of a JWT, sign it using the algorithm given and return
70/// the base64 url safe encoded of the result.
71///
72/// If you just want to encode a JWT, use `encode` instead.
73pub fn sign(message: &str, key: &EncodingKey, algorithm: Algorithm) -> Result<String> {
74    match key {
75        EncodingKey::Hmac(s) => match algorithm {
76            Algorithm::HS256 => sign_hmac(Algorithm::HS256, s, message),
77            Algorithm::HS384 => sign_hmac(Algorithm::HS384, s, message),
78            Algorithm::HS512 => sign_hmac(Algorithm::HS512, s, message),
79            _ => Err(ErrorKind::InvalidAlgorithm.into()),
80        },
81
82        EncodingKey::Rsa(k) => match algorithm {
83            Algorithm::RS256
84            | Algorithm::RS384
85            | Algorithm::RS512
86            | Algorithm::PS256
87            | Algorithm::PS384
88            | Algorithm::PS512 => rsa::sign(algorithm, k, message),
89            _ => Err(ErrorKind::InvalidAlgorithm.into()),
90        },
91        // EncodingKey::EcPkcs8(k)
92        //     => match algorithm {
93        //         Algorithm::ES256 | Algorithm::ES384 => {
94        //             ecdsa::sign_pkcs8(ecdsa::alg_to_ec_signing(algorithm), k, message)
95        //         },
96        //         _ => Err(ErrorKind::InvalidAlgorithm.into())
97        //     }
98    }
99}
100
101/// Compares the signature given with a re-computed signature for HMAC or using the public key
102/// for RSA/EC.
103///
104/// If you just want to decode a JWT, use `decode` instead.
105///
106/// `signature` is the signature part of a jwt (text after the second '.')
107///
108/// `message` is base64(header) + "." + base64(claims)
109pub fn verify(
110    signature: &str,
111    message: &str,
112    key: &DecodingKey,
113    algorithm: Algorithm,
114) -> Result<bool> {
115    match key {
116        DecodingKey::Hmac(s) => match algorithm {
117            Algorithm::HS256 => {
118                let mut mac = HmacSha256::new_from_slice(s).unwrap();
119                mac.update(message.as_bytes());
120                Ok(mac.finalize().into_bytes().as_slice()
121                    == b64_decode(signature)
122                        .map_err(|_e| new_error(ErrorKind::InvalidSignature))?)
123            }
124            Algorithm::HS384 => {
125                let mut mac = HmacSha384::new_from_slice(s).unwrap();
126                mac.update(message.as_bytes());
127                Ok(mac.finalize().into_bytes().as_slice()
128                    == b64_decode(signature)
129                        .map_err(|_e| new_error(ErrorKind::InvalidSignature))?)
130            }
131            Algorithm::HS512 => {
132                let mut mac = HmacSha512::new_from_slice(s).unwrap();
133                mac.update(message.as_bytes());
134                Ok(mac.finalize().into_bytes().as_slice()
135                    == b64_decode(signature)
136                        .map_err(|_e| new_error(ErrorKind::InvalidSignature))?)
137            }
138            _ => Err(ErrorKind::InvalidAlgorithm.into()),
139        },
140        DecodingKey::Rsa(k) => match algorithm {
141            Algorithm::RS256
142            | Algorithm::RS384
143            | Algorithm::RS512
144            | Algorithm::PS256
145            | Algorithm::PS384
146            | Algorithm::PS512 => rsa::verify(algorithm, signature, message, k),
147            _ => Err(ErrorKind::InvalidAlgorithm.into()),
148        },
149    }
150}