Skip to main content

ssh_key/public/
rsa.rs

1//! Rivest–Shamir–Adleman (RSA) public keys.
2
3use crate::{Error, Mpint, Result};
4use core::hash::{Hash, Hasher};
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6
7#[cfg(feature = "rsa")]
8use {
9    encoding::Uint,
10    rsa::{pkcs1v15, traits::PublicKeyParts},
11    sha2::{Digest, digest::const_oid::AssociatedOid},
12};
13
14/// RSA public key.
15///
16/// Described in [RFC4253 § 6.6](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6).
17#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
18pub struct RsaPublicKey {
19    /// RSA public exponent.
20    e: Mpint,
21
22    /// RSA modulus.
23    n: Mpint,
24
25    /// Length of this key in bits.
26    bits: u32,
27}
28
29impl RsaPublicKey {
30    /// Create a new [`RsaPublicKey`] with the given components:
31    ///
32    /// - `e`: RSA public exponent.
33    /// - `n`: RSA modulus.
34    ///
35    /// # Errors
36    /// Returns [`Error::FormatEncoding`] in the event one of the components is odd.
37    pub fn new(e: Mpint, n: Mpint) -> Result<Self> {
38        if !e.is_positive() {
39            return Err(Error::FormatEncoding);
40        }
41
42        let bits = match n.as_positive_bytes() {
43            Some(bytes) => bytes
44                .len()
45                .checked_mul(8)
46                .and_then(|bits| u32::try_from(bits).ok())
47                .ok_or(Error::FormatEncoding)?,
48            None => return Err(Error::FormatEncoding),
49        };
50
51        Ok(Self { e, n, bits })
52    }
53
54    /// Get the RSA public exponent.
55    #[must_use]
56    pub fn e(&self) -> &Mpint {
57        &self.e
58    }
59
60    /// Get the RSA modulus.
61    #[must_use]
62    pub fn n(&self) -> &Mpint {
63        &self.n
64    }
65
66    /// Get the size of the RSA modulus in bits.
67    #[must_use]
68    pub fn key_size(&self) -> u32 {
69        self.bits
70    }
71}
72
73impl Decode for RsaPublicKey {
74    type Error = Error;
75
76    fn decode(reader: &mut impl Reader) -> Result<Self> {
77        let e = Mpint::decode(reader)?;
78        let n = Mpint::decode(reader)?;
79        Self::new(e, n)
80    }
81}
82
83impl Encode for RsaPublicKey {
84    fn encoded_len(&self) -> encoding::Result<usize> {
85        [self.e.encoded_len()?, self.n.encoded_len()?].checked_sum()
86    }
87
88    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
89        self.e.encode(writer)?;
90        self.n.encode(writer)
91    }
92}
93
94impl Hash for RsaPublicKey {
95    #[inline]
96    fn hash<H: Hasher>(&self, state: &mut H) {
97        self.e.as_bytes().hash(state);
98        self.n.as_bytes().hash(state);
99    }
100}
101
102#[cfg(feature = "rsa")]
103impl TryFrom<RsaPublicKey> for rsa::RsaPublicKey {
104    type Error = Error;
105
106    fn try_from(key: RsaPublicKey) -> Result<rsa::RsaPublicKey> {
107        rsa::RsaPublicKey::try_from(&key)
108    }
109}
110
111#[cfg(feature = "rsa")]
112impl TryFrom<&RsaPublicKey> for rsa::RsaPublicKey {
113    type Error = Error;
114
115    fn try_from(key: &RsaPublicKey) -> Result<rsa::RsaPublicKey> {
116        let n = Uint::try_from(&key.n)?;
117        let e = Uint::try_from(&key.e)?;
118        let ret = rsa::RsaPublicKey::new(n, e).map_err(|_| Error::Crypto)?;
119
120        Ok(ret)
121    }
122}
123
124#[cfg(feature = "rsa")]
125impl TryFrom<rsa::RsaPublicKey> for RsaPublicKey {
126    type Error = Error;
127
128    fn try_from(key: rsa::RsaPublicKey) -> Result<RsaPublicKey> {
129        RsaPublicKey::try_from(&key)
130    }
131}
132
133#[cfg(feature = "rsa")]
134impl TryFrom<&rsa::RsaPublicKey> for RsaPublicKey {
135    type Error = Error;
136
137    fn try_from(key: &rsa::RsaPublicKey) -> Result<RsaPublicKey> {
138        RsaPublicKey::new(key.e().into(), key.n().as_ref().into())
139    }
140}
141
142#[cfg(feature = "rsa")]
143impl<D> TryFrom<&RsaPublicKey> for pkcs1v15::VerifyingKey<D>
144where
145    D: Digest + AssociatedOid,
146{
147    type Error = Error;
148
149    fn try_from(key: &RsaPublicKey) -> Result<pkcs1v15::VerifyingKey<D>> {
150        Ok(pkcs1v15::VerifyingKey::new(key.try_into()?))
151    }
152}