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    cached_public_key_pem: Vec<u8>,
17}
18
19impl RsaSigner {
20    fn from_key_pair(
21        private_key: RsaPrivateKey,
22        public_key: RsaPublicKey,
23    ) -> Result<Self, SignerError> {
24        let cached_public_key_pem = public_key
25            .to_public_key_pem(pkcs8::LineEnding::LF)
26            .map_err(|e| SignerError::Pkcs8(e.to_string()))?
27            .into_bytes();
28        Ok(Self {
29            private_key,
30            public_key,
31            cached_public_key_pem,
32        })
33    }
34
35    pub fn generate(key_size: usize) -> Result<Self, SignerError> {
36        let private_key = RsaPrivateKey::new(&mut OsRng, key_size)
37            .map_err(|e| SignerError::Rsa(e.to_string()))?;
38        let public_key = private_key.to_public_key();
39        Self::from_key_pair(private_key, public_key)
40    }
41
42    pub fn from_pem(pem: &str) -> Result<Self, SignerError> {
43        use crate::pem_loader::{PemKind, classify_pem};
44
45        let private_key =
46            match classify_pem(pem) {
47                PemKind::Pkcs1Rsa => RsaPrivateKey::from_pkcs1_pem(pem)
48                    .map_err(|e| SignerError::Rsa(e.to_string()))?,
49                PemKind::Pkcs8 => RsaPrivateKey::from_pkcs8_pem(pem)
50                    .map_err(|e| SignerError::Pkcs8(e.to_string()))?,
51                _ => return Err(SignerError::UnknownKeyFormat),
52            };
53
54        let public_key = private_key.to_public_key();
55        Self::from_key_pair(private_key, public_key)
56    }
57
58    pub fn to_pem(&self) -> Result<String, SignerError> {
59        use pkcs8::EncodePrivateKey;
60
61        self.private_key
62            .to_pkcs8_pem(pkcs8::LineEnding::LF)
63            .map(|pem| pem.to_string())
64            .map_err(|e| SignerError::Pkcs8(e.to_string()))
65    }
66
67    pub fn public_key_to_pem(&self) -> Result<String, SignerError> {
68        self.public_key
69            .to_public_key_pem(pkcs8::LineEnding::LF)
70            .map_err(|e| SignerError::Pkcs8(e.to_string()))
71    }
72
73    pub fn verify_with_public_key(
74        data: &[u8],
75        public_key_pem: &[u8],
76        signature: &[u8],
77    ) -> Result<(), SignerError> {
78        let public_key_str = std::str::from_utf8(public_key_pem)
79            .map_err(|e| SignerError::InvalidPublicKey(e.to_string()))?;
80        let public_key = RsaPublicKey::from_public_key_pem(public_key_str)
81            .map_err(|e| SignerError::InvalidPublicKey(e.to_string()))?;
82        let hash = Sha256::digest(data);
83        public_key
84            .verify(Pkcs1v15Sign::new::<Sha256>(), &hash, signature)
85            .map_err(|_| SignerError::VerificationFailed)
86    }
87}
88
89impl Signer for RsaSigner {
90    fn algorithm(&self) -> &'static str {
91        "rsa"
92    }
93
94    fn public_key(&self) -> &[u8] {
95        &self.cached_public_key_pem
96    }
97
98    fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SignerError> {
99        let hash = Sha256::digest(data);
100        self.private_key
101            .sign(Pkcs1v15Sign::new::<Sha256>(), &hash)
102            .map_err(|e| SignerError::Rsa(e.to_string()))
103    }
104
105    fn verify(&self, data: &[u8], signature: &[u8]) -> Result<(), SignerError> {
106        let hash = Sha256::digest(data);
107        self.public_key
108            .verify(Pkcs1v15Sign::new::<Sha256>(), &hash, signature)
109            .map_err(|_| SignerError::VerificationFailed)
110    }
111}