ssh_key/public/
rsa.rs

1//! Rivest–Shamir–Adleman (RSA) public keys.
2
3use crate::{
4    checked::CheckedSum, decode::Decode, encode::Encode, reader::Reader, writer::Writer, MPInt,
5    Result,
6};
7
8#[cfg(feature = "rsa")]
9use {
10    crate::{private::RsaKeypair, Error},
11    rsa::PublicKeyParts,
12};
13
14/// RSA public key.
15///
16/// Described in [RFC4253 § 6.6](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6):
17#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
18#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
19pub struct RsaPublicKey {
20    /// RSA public exponent.
21    pub e: MPInt,
22
23    /// RSA modulus.
24    pub n: MPInt,
25}
26
27impl RsaPublicKey {
28    /// Minimum allowed RSA key size.
29    #[cfg(feature = "rsa")]
30    pub(crate) const MIN_KEY_SIZE: usize = RsaKeypair::MIN_KEY_SIZE;
31}
32
33impl Decode for RsaPublicKey {
34    fn decode(reader: &mut impl Reader) -> Result<Self> {
35        let e = MPInt::decode(reader)?;
36        let n = MPInt::decode(reader)?;
37        Ok(Self { e, n })
38    }
39}
40
41impl Encode for RsaPublicKey {
42    fn encoded_len(&self) -> Result<usize> {
43        [self.e.encoded_len()?, self.n.encoded_len()?].checked_sum()
44    }
45
46    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
47        self.e.encode(writer)?;
48        self.n.encode(writer)
49    }
50}
51
52#[cfg(feature = "rsa")]
53#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
54impl TryFrom<RsaPublicKey> for rsa::RsaPublicKey {
55    type Error = Error;
56
57    fn try_from(key: RsaPublicKey) -> Result<rsa::RsaPublicKey> {
58        rsa::RsaPublicKey::try_from(&key)
59    }
60}
61
62#[cfg(feature = "rsa")]
63#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
64impl TryFrom<&RsaPublicKey> for rsa::RsaPublicKey {
65    type Error = Error;
66
67    fn try_from(key: &RsaPublicKey) -> Result<rsa::RsaPublicKey> {
68        let ret = rsa::RsaPublicKey::new(
69            rsa::BigUint::try_from(&key.n)?,
70            rsa::BigUint::try_from(&key.e)?,
71        )
72        .map_err(|_| Error::Crypto)?;
73
74        if ret.size().saturating_mul(8) >= RsaPublicKey::MIN_KEY_SIZE {
75            Ok(ret)
76        } else {
77            Err(Error::Crypto)
78        }
79    }
80}
81
82#[cfg(feature = "rsa")]
83#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
84impl TryFrom<rsa::RsaPublicKey> for RsaPublicKey {
85    type Error = Error;
86
87    fn try_from(key: rsa::RsaPublicKey) -> Result<RsaPublicKey> {
88        RsaPublicKey::try_from(&key)
89    }
90}
91
92#[cfg(feature = "rsa")]
93#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
94impl TryFrom<&rsa::RsaPublicKey> for RsaPublicKey {
95    type Error = Error;
96
97    fn try_from(key: &rsa::RsaPublicKey) -> Result<RsaPublicKey> {
98        Ok(RsaPublicKey {
99            e: key.e().try_into()?,
100            n: key.n().try_into()?,
101        })
102    }
103}