Skip to main content

crypto/
rsa.rs

1// SPDX-License-Identifier: Apache-2.0
2//! RSA signature implementation.
3
4use pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePublicKey};
5use rsa::{
6    Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey, pkcs1::DecodeRsaPrivateKey, rand_core::OsRng,
7};
8use sha2::{Digest, Sha256};
9
10use crate::{Signer, SignerError};
11
12/// RSA signer.
13pub struct RsaSigner {
14    private_key: RsaPrivateKey,
15    public_key: RsaPublicKey,
16}
17
18impl RsaSigner {
19    pub fn generate(key_size: usize) -> Result<Self, SignerError> {
20        let private_key = RsaPrivateKey::new(&mut OsRng, key_size)
21            .map_err(|e| SignerError::Rsa(e.to_string()))?;
22        let public_key = private_key.to_public_key();
23
24        Ok(Self {
25            private_key,
26            public_key,
27        })
28    }
29
30    pub fn from_pem(pem: &str) -> Result<Self, SignerError> {
31        let private_key = if pem.contains("-----BEGIN RSA PRIVATE KEY-----") {
32            RsaPrivateKey::from_pkcs1_pem(pem).map_err(|e| SignerError::Rsa(e.to_string()))?
33        } else if pem.contains("-----BEGIN PRIVATE KEY-----") {
34            RsaPrivateKey::from_pkcs8_pem(pem).map_err(|e| SignerError::Pkcs8(e.to_string()))?
35        } else {
36            return Err(SignerError::UnknownKeyFormat);
37        };
38
39        let public_key = private_key.to_public_key();
40        Ok(Self {
41            private_key,
42            public_key,
43        })
44    }
45
46    pub fn to_pem(&self) -> Result<String, SignerError> {
47        use pkcs8::EncodePrivateKey;
48
49        self.private_key
50            .to_pkcs8_pem(pkcs8::LineEnding::LF)
51            .map(|pem| pem.to_string())
52            .map_err(|e| SignerError::Pkcs8(e.to_string()))
53    }
54
55    pub fn public_key_to_pem(&self) -> Result<String, SignerError> {
56        self.public_key
57            .to_public_key_pem(pkcs8::LineEnding::LF)
58            .map_err(|e| SignerError::Pkcs8(e.to_string()))
59    }
60
61    pub fn verify_with_public_key(
62        data: &[u8],
63        public_key_pem: &[u8],
64        signature: &[u8],
65    ) -> Result<(), SignerError> {
66        let public_key_str = std::str::from_utf8(public_key_pem)
67            .map_err(|e| SignerError::InvalidPublicKey(e.to_string()))?;
68        let public_key = RsaPublicKey::from_public_key_pem(public_key_str)
69            .map_err(|e| SignerError::InvalidPublicKey(e.to_string()))?;
70        let hash = Sha256::digest(data);
71        public_key
72            .verify(Pkcs1v15Sign::new::<Sha256>(), &hash, signature)
73            .map_err(|_| SignerError::VerificationFailed)
74    }
75}
76
77impl Signer for RsaSigner {
78    fn algorithm(&self) -> &'static str {
79        "rsa"
80    }
81
82    fn public_key(&self) -> Vec<u8> {
83        self.public_key_to_pem()
84            .unwrap_or_default()
85            .as_bytes()
86            .to_vec()
87    }
88
89    fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SignerError> {
90        let hash = Sha256::digest(data);
91        self.private_key
92            .sign(Pkcs1v15Sign::new::<Sha256>(), &hash)
93            .map_err(|e| SignerError::Rsa(e.to_string()))
94    }
95
96    fn verify(&self, data: &[u8], signature: &[u8]) -> Result<(), SignerError> {
97        let hash = Sha256::digest(data);
98        self.public_key
99            .verify(Pkcs1v15Sign::new::<Sha256>(), &hash, signature)
100            .map_err(|_| SignerError::VerificationFailed)
101    }
102}