jsonwebtoken_rustcrypto/crypto/
rsa.rs

1// use ring::{rand, signature};
2use crate::errors::{ErrorKind, Result};
3use crate::serialization::{b64_decode, b64_encode};
4use crate::{errors, Algorithm};
5use rsa::SignatureScheme;
6use rsa::{pss::Pss, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey};
7use sha2::{Digest, Sha256, Sha384, Sha512};
8
9/// The actual RSA signing + encoding
10/// The key needs to be in binary DER-encoded ASN.1 format
11/// Taken from Ring doc https://briansmith.org/rustdoc/ring/signature/index.html
12pub(crate) fn sign(alg: Algorithm, key: &RsaPrivateKey, message: &str) -> Result<String> {
13    let digest: Vec<u8> = match alg {
14        // PaddingScheme::OAEP {digest, ..} => {
15        //     digest.update(message.as_bytes());
16        //     digest.finalize_reset()
17        // },
18        // None => message.as_bytes().into(),
19        Algorithm::RS256 | Algorithm::PS256 => {
20            let mut hasher = Sha256::new();
21            hasher.update(message.as_bytes());
22            let d = hasher.finalize();
23            d.as_slice().to_vec()
24        }
25        Algorithm::RS384 | Algorithm::PS384 => {
26            let mut hasher = Sha384::new();
27            hasher.update(message.as_bytes());
28            let d = hasher.finalize();
29            d.as_slice().to_vec()
30        }
31        Algorithm::RS512 | Algorithm::PS512 => {
32            let mut hasher = Sha512::new();
33            hasher.update(message.as_bytes());
34            let d = hasher.finalize();
35            d.as_slice().to_vec()
36        }
37        _ => unimplemented!(),
38    };
39
40    let signatures_scheme_pkcs = match alg {
41        Algorithm::RS256 => Some(Pkcs1v15Sign::new::<Sha256>()),
42        Algorithm::RS384 => Some(Pkcs1v15Sign::new::<Sha384>()),
43        Algorithm::RS512 => Some(Pkcs1v15Sign::new::<Sha512>()),
44        _ => None,
45    };
46
47    let signatures_scheme_pss = match alg {
48        Algorithm::PS256 => Some(Pss::new_with_salt::<Sha256>(digest.len())),
49        Algorithm::PS384 => Some(Pss::new_with_salt::<Sha384>(digest.len())),
50        Algorithm::PS512 => Some(Pss::new_with_salt::<Sha512>(digest.len())),
51        _ => None,
52    };
53
54    let mut rng = rand::thread_rng();
55
56    let signature = if let Some(signatures_scheme) = signatures_scheme_pkcs {
57        // In versions pre 1.2.0, signatures did not use RNG.
58        signatures_scheme.sign(Some(&mut rng), key, &digest).expect("failed to sign pkcs")
59    } else if let Some(signatures_scheme) = signatures_scheme_pss {
60        // PSS requires signing with RNG,otherwise it errors at runtime.
61        signatures_scheme.sign(Some(&mut rng), key, &digest).expect("failed to sign pss")
62    } else {
63        return Err(ErrorKind::InvalidAlgorithmName.into());
64    };
65
66    Ok(b64_encode(&signature))
67}
68
69/// Checks that a signature is valid based on the (n, e) RSA pubkey components
70pub(crate) fn verify(
71    alg: Algorithm,
72    signature: &str,
73    message: &str,
74    key: &RsaPublicKey,
75) -> Result<bool> {
76    let digest: Vec<u8> = match alg {
77        // PaddingScheme::OAEP {digest, ..} => {
78        //     digest.update(message.as_bytes());
79        //     digest.finalize_reset()
80        // },
81        // None => message.as_bytes().into(),
82        Algorithm::RS256 | Algorithm::PS256 => {
83            let mut hasher = Sha256::new();
84            hasher.update(message.as_bytes());
85            let d = hasher.finalize();
86            d.iter().copied().collect()
87        }
88        Algorithm::RS384 | Algorithm::PS384 => {
89            let mut hasher = Sha384::new();
90            hasher.update(message.as_bytes());
91            let d = hasher.finalize();
92            d.iter().copied().collect()
93        }
94        Algorithm::RS512 | Algorithm::PS512 => {
95            let mut hasher = Sha512::new();
96            hasher.update(message.as_bytes());
97            let d = hasher.finalize();
98            d.iter().copied().collect()
99        }
100        // Algorithm::PS256 | Algorithm::PS384 | Algorithm::PS512 => {
101        //     message.as_bytes().to_vec()
102        // }
103        _ => unimplemented!(),
104    };
105
106    let signature_bytes = b64_decode(signature)?;
107
108    let signatures_scheme_pkcs = match alg {
109        Algorithm::RS256 => Some(Pkcs1v15Sign::new::<Sha256>()),
110        Algorithm::RS384 => Some(Pkcs1v15Sign::new::<Sha384>()),
111        Algorithm::RS512 => Some(Pkcs1v15Sign::new::<Sha512>()),
112        _ => None,
113    };
114
115    let signatures_scheme_pss = match alg {
116        Algorithm::PS256 => Some(Pss::new_with_salt::<Sha256>(digest.len())),
117        Algorithm::PS384 => Some(Pss::new_with_salt::<Sha384>(digest.len())),
118        Algorithm::PS512 => Some(Pss::new_with_salt::<Sha512>(digest.len())),
119        _ => None,
120    };
121
122    if let Some(signatures_scheme) = signatures_scheme_pkcs {
123        signatures_scheme
124            .verify(key, &digest, &signature_bytes)
125            .map_err(|_| errors::new_error(ErrorKind::InvalidSignature))?;
126    } else if let Some(signatures_scheme) = signatures_scheme_pss {
127        signatures_scheme
128            .verify(key, &digest, &signature_bytes)
129            .map_err(|_| errors::new_error(ErrorKind::InvalidSignature))?;
130    } else {
131        return Err(ErrorKind::InvalidAlgorithmName.into());
132    };
133
134    Ok(true)
135}