1use crate::error::{FastCryptoError, FastCryptoResult};
7use crate::hash::{HashFunction, Sha256};
8pub use base64ct::{Base64UrlUnpadded, Encoding};
9use rsa::pkcs1::DecodeRsaPublicKey;
10use rsa::pkcs1v15::Signature as ExternalSignature;
11use rsa::{BigUint, RsaPublicKey as ExternalPublicKey};
12use rsa::{Pkcs1v15Sign, PublicKey};
13
14#[derive(Clone)]
15pub struct RSAPublicKey(pub ExternalPublicKey);
16
17#[derive(Clone, PartialEq, Eq)]
18pub struct RSASignature(pub ExternalSignature);
19
20impl RSAPublicKey {
21 pub fn from_der(der: &[u8]) -> FastCryptoResult<Self> {
23 Ok(RSAPublicKey(
24 rsa::RsaPublicKey::from_pkcs1_der(der).map_err(|_| FastCryptoError::InvalidInput)?,
25 ))
26 }
27
28 pub fn from_raw_components(modulus: &[u8], exponent: &[u8]) -> FastCryptoResult<Self> {
30 Ok(RSAPublicKey(
32 rsa::RsaPublicKey::new(
33 BigUint::from_bytes_be(modulus),
34 BigUint::from_bytes_be(exponent),
35 )
36 .map_err(|_| FastCryptoError::InvalidInput)?,
37 ))
38 }
39
40 pub fn verify(&self, msg: &[u8], signature: &RSASignature) -> FastCryptoResult<()> {
42 self.verify_prehash(&Sha256::digest(msg).digest, signature)
43 }
44
45 pub fn verify_prehash(&self, hashed: &[u8], signature: &RSASignature) -> FastCryptoResult<()> {
47 self.0
48 .verify(
49 Pkcs1v15Sign::new::<sha2::Sha256>(),
50 hashed,
51 signature.0.as_ref(),
52 )
53 .map_err(|_| FastCryptoError::InvalidSignature)
54 }
55}
56
57impl RSASignature {
58 pub fn from_bytes(bytes: &[u8]) -> FastCryptoResult<Self> {
60 Ok(Self(
61 ExternalSignature::try_from(bytes).map_err(|_| FastCryptoError::InvalidInput)?,
62 ))
63 }
64}
65
66#[cfg(test)]
67mod test {
68 use crate::hash::{HashFunction, Sha256};
69 use crate::rsa::{Base64UrlUnpadded, Encoding};
70 use crate::rsa::{RSAPublicKey, RSASignature};
71
72 #[test]
73 fn jwt_test() {
74 let n_base64 = "ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ";
76 let n_bytes = Base64UrlUnpadded::decode_vec(n_base64).unwrap();
77
78 let e_base64 = "AQAB";
79 let e_bytes = Base64UrlUnpadded::decode_vec(e_base64).unwrap();
80
81 let pk = RSAPublicKey::from_raw_components(&n_bytes, &e_bytes).unwrap();
82
83 let msg = b"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ";
84 let digest = Sha256::digest(msg).digest;
85
86 let signature_base64 = "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw";
87 let signature_bytes = Base64UrlUnpadded::decode_vec(signature_base64).unwrap();
88 let signature = RSASignature::from_bytes(&signature_bytes).unwrap();
89
90 assert!(pk.verify_prehash(&digest, &signature).is_ok());
92 assert!(pk.verify(msg, &signature).is_ok());
93
94 let mut other_digest = digest;
96 other_digest[0] += 1;
97 assert!(pk.verify_prehash(&other_digest, &signature).is_err());
98
99 let mut other_msg = *msg;
101 other_msg[0] += 1;
102 assert!(pk.verify(&other_msg, &signature).is_err());
103
104 let mut other_signature_bytes = signature_bytes;
106 other_signature_bytes[7] += 1;
107 let other_signature = RSASignature::from_bytes(&other_signature_bytes).unwrap();
108 assert!(pk.verify_prehash(&other_digest, &signature).is_err());
109 assert!(pk.verify(msg, &other_signature).is_err());
110 }
111}