1use crate::{Error, Mpint, Result};
4use core::hash::{Hash, Hasher};
5use encoding::{CheckedSum, Decode, Encode, Reader, Writer};
6
7#[cfg(feature = "rsa")]
8use {
9 crate::private::RsaKeypair,
10 encoding::Uint,
11 rsa::{pkcs1v15, traits::PublicKeyParts},
12 sha2::{Digest, digest::const_oid::AssociatedOid},
13};
14
15#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
19pub struct RsaPublicKey {
20 e: Mpint,
22
23 n: Mpint,
25
26 bits: u32,
28}
29
30impl RsaPublicKey {
31 #[cfg(feature = "rsa")]
33 pub(crate) const MIN_KEY_SIZE: usize = RsaKeypair::MIN_KEY_SIZE;
34
35 pub fn new(e: Mpint, n: Mpint) -> Result<Self> {
40 if !e.is_positive() {
41 return Err(Error::FormatEncoding);
42 }
43
44 let bits = match n.as_positive_bytes() {
45 Some(bytes) => bytes
46 .len()
47 .checked_mul(8)
48 .and_then(|bits| u32::try_from(bits).ok())
49 .ok_or(Error::FormatEncoding)?,
50 None => return Err(Error::FormatEncoding),
51 };
52
53 Ok(Self { e, n, bits })
54 }
55
56 pub fn e(&self) -> &Mpint {
58 &self.e
59 }
60
61 pub fn n(&self) -> &Mpint {
63 &self.n
64 }
65
66 pub fn key_size(&self) -> u32 {
68 self.bits
69 }
70}
71
72impl Decode for RsaPublicKey {
73 type Error = Error;
74
75 fn decode(reader: &mut impl Reader) -> Result<Self> {
76 let e = Mpint::decode(reader)?;
77 let n = Mpint::decode(reader)?;
78 Self::new(e, n)
79 }
80}
81
82impl Encode for RsaPublicKey {
83 fn encoded_len(&self) -> encoding::Result<usize> {
84 [self.e.encoded_len()?, self.n.encoded_len()?].checked_sum()
85 }
86
87 fn encode(&self, writer: &mut impl Writer) -> encoding::Result<()> {
88 self.e.encode(writer)?;
89 self.n.encode(writer)
90 }
91}
92
93impl Hash for RsaPublicKey {
94 #[inline]
95 fn hash<H: Hasher>(&self, state: &mut H) {
96 self.e.as_bytes().hash(state);
97 self.n.as_bytes().hash(state);
98 }
99}
100
101#[cfg(feature = "rsa")]
102impl TryFrom<RsaPublicKey> for rsa::RsaPublicKey {
103 type Error = Error;
104
105 fn try_from(key: RsaPublicKey) -> Result<rsa::RsaPublicKey> {
106 rsa::RsaPublicKey::try_from(&key)
107 }
108}
109
110#[cfg(feature = "rsa")]
111impl TryFrom<&RsaPublicKey> for rsa::RsaPublicKey {
112 type Error = Error;
113
114 fn try_from(key: &RsaPublicKey) -> Result<rsa::RsaPublicKey> {
115 let n = Uint::try_from(&key.n)?;
116 let e = Uint::try_from(&key.e)?;
117 let ret = rsa::RsaPublicKey::new(n, e).map_err(|_| Error::Crypto)?;
118
119 if ret.size().saturating_mul(8) >= RsaPublicKey::MIN_KEY_SIZE {
120 Ok(ret)
121 } else {
122 Err(Error::Crypto)
123 }
124 }
125}
126
127#[cfg(feature = "rsa")]
128impl TryFrom<rsa::RsaPublicKey> for RsaPublicKey {
129 type Error = Error;
130
131 fn try_from(key: rsa::RsaPublicKey) -> Result<RsaPublicKey> {
132 RsaPublicKey::try_from(&key)
133 }
134}
135
136#[cfg(feature = "rsa")]
137impl TryFrom<&rsa::RsaPublicKey> for RsaPublicKey {
138 type Error = Error;
139
140 fn try_from(key: &rsa::RsaPublicKey) -> Result<RsaPublicKey> {
141 let e = Mpint::try_from(key.e())?;
142 let n = Mpint::try_from(key.n().as_ref())?;
143 RsaPublicKey::new(e, n)
144 }
145}
146
147#[cfg(feature = "rsa")]
148impl<D> TryFrom<&RsaPublicKey> for pkcs1v15::VerifyingKey<D>
149where
150 D: Digest + AssociatedOid,
151{
152 type Error = Error;
153
154 fn try_from(key: &RsaPublicKey) -> Result<pkcs1v15::VerifyingKey<D>> {
155 Ok(pkcs1v15::VerifyingKey::new(key.try_into()?))
156 }
157}