Skip to main content

ssh_key_fork_arti/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    rsa::{pkcs1v15, traits::PublicKeyParts},
10    sha2::{digest::const_oid::AssociatedOid, Digest},
11};
12
13/// RSA public key.
14///
15/// Described in [RFC4253 § 6.6](https://datatracker.ietf.org/doc/html/rfc4253#section-6.6).
16#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
17pub struct RsaPublicKey {
18    /// RSA public exponent.
19    pub e: Mpint,
20
21    /// RSA modulus.
22    pub n: Mpint,
23}
24
25impl RsaPublicKey {}
26
27impl Decode for RsaPublicKey {
28    type Error = Error;
29
30    fn decode(reader: &mut impl Reader) -> Result<Self> {
31        let e = Mpint::decode(reader)?;
32        let n = Mpint::decode(reader)?;
33        Ok(Self { e, n })
34    }
35}
36
37impl Encode for RsaPublicKey {
38    fn encoded_len(&self) -> encoding::Result<usize> {
39        [self.e.encoded_len()?, self.n.encoded_len()?].checked_sum()
40    }
41
42    fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
43        self.e.encode(writer)?;
44        self.n.encode(writer)
45    }
46}
47
48impl Hash for RsaPublicKey {
49    #[inline]
50    fn hash<H: Hasher>(&self, state: &mut H) {
51        self.e.as_bytes().hash(state);
52        self.n.as_bytes().hash(state);
53    }
54}
55
56#[cfg(feature = "rsa")]
57impl TryFrom<RsaPublicKey> for rsa::RsaPublicKey {
58    type Error = Error;
59
60    fn try_from(key: RsaPublicKey) -> Result<rsa::RsaPublicKey> {
61        rsa::RsaPublicKey::try_from(&key)
62    }
63}
64
65#[cfg(feature = "rsa")]
66impl TryFrom<&RsaPublicKey> for rsa::RsaPublicKey {
67    type Error = Error;
68
69    fn try_from(key: &RsaPublicKey) -> Result<rsa::RsaPublicKey> {
70        let ret = rsa::RsaPublicKey::new(
71            rsa::BigUint::try_from(&key.n)?,
72            rsa::BigUint::try_from(&key.e)?,
73        )
74        .map_err(|_| Error::Crypto)?;
75
76        Ok(ret)
77    }
78}
79
80#[cfg(feature = "rsa")]
81impl TryFrom<rsa::RsaPublicKey> for RsaPublicKey {
82    type Error = Error;
83
84    fn try_from(key: rsa::RsaPublicKey) -> Result<RsaPublicKey> {
85        RsaPublicKey::try_from(&key)
86    }
87}
88
89#[cfg(feature = "rsa")]
90impl TryFrom<&rsa::RsaPublicKey> for RsaPublicKey {
91    type Error = Error;
92
93    fn try_from(key: &rsa::RsaPublicKey) -> Result<RsaPublicKey> {
94        Ok(RsaPublicKey {
95            e: key.e().try_into()?,
96            n: key.n().try_into()?,
97        })
98    }
99}
100
101#[cfg(feature = "rsa")]
102impl<D> TryFrom<&RsaPublicKey> for pkcs1v15::VerifyingKey<D>
103where
104    D: Digest + AssociatedOid,
105{
106    type Error = Error;
107
108    fn try_from(key: &RsaPublicKey) -> Result<pkcs1v15::VerifyingKey<D>> {
109        Ok(pkcs1v15::VerifyingKey::new(key.try_into()?))
110    }
111}