1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
//! RSA public key type.
use crate::traits::{PaddingScheme, PublicKeyParts, SignatureScheme};
use crate::{Error, Result, RsaPrivateKey};
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
use core::ops::RangeInclusive;
use crypto_bigint::modular::BoxedMontyParams;
use crypto_bigint::{BoxedUint, Integer, NonZero, Odd};
use rand_core::CryptoRng;
#[cfg(feature = "serde")]
use {
serdect::serde::{Deserialize, Serialize, de, ser},
spki::{DecodePublicKey, EncodePublicKey},
};
/// Represents the public part of an RSA key.
#[derive(Debug, Clone)]
pub struct RsaPublicKey {
/// Modulus: product of prime numbers `p` and `q`
pub(crate) n: NonZero<BoxedUint>,
/// Public exponent: power to which a plaintext message is raised in
/// order to encrypt it.
///
/// The recommended value is `0x10001` (`65537`).
pub(crate) e: BoxedUint,
/// `n` represented as its Montgomery parameters.
pub(crate) n_params: BoxedMontyParams,
}
impl RsaPublicKey {
/// Default minimum size of the modulus `n` in bits.
pub const MIN_SIZE: usize = 1024;
/// Default maximum size of the modulus `n` in bits.
pub const MAX_SIZE: usize = 8192;
/// Minimum value of the public exponent `e`.
pub const MIN_PUB_EXPONENT: u64 = 2;
/// Maximum value of the public exponent `e`.
///
/// Very large public exponents are a potential denial-of-service vector (a.k.a. "RSADoS")
/// because they increase the amount of work required for e.g. signature verification. See:
///
/// <https://www.imperialviolet.org/2012/03/17/rsados.html>
///
/// The particular constant below has been chosen to align with *ring* where this value was
/// selected based on the history of this particular issue, API compatibility concerns, and
/// benchmark-driven evaluation. See RustCrypto/RSA#155.
///
/// If for some reason you have a legitimate reason to use keys with public exponents larger
/// than this value, use the special APIs:
///
/// - [`RsaPublicKey::new_unchecked`]
/// - [`RsaPrivateKey::from_components_with_large_exponent`]
pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
/// Encrypt the given message.
#[allow(clippy::missing_errors_doc, reason = "TODO")]
pub fn encrypt<R: CryptoRng + ?Sized, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
msg: &[u8],
) -> Result<Vec<u8>> {
padding.encrypt(rng, self, msg)
}
/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
#[allow(clippy::missing_errors_doc, reason = "TODO")]
pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
scheme.verify(self, hashed, sig)
}
/// Create a new public key from its components.
///
/// Accepts modulus sizes from [`Self::MIN_SIZE`] to [`Self::MAX_SIZE`], inclusive.
/// Use [`Self::new_with_size_limits`] to explicitly allow other sizes.
#[allow(clippy::missing_errors_doc, reason = "TODO")]
pub fn new(n: BoxedUint, e: BoxedUint) -> Result<Self> {
Self::new_with_size_limits(n, e, Self::MIN_SIZE..=Self::MAX_SIZE)
}
/// Create a new public key with explicit, inclusive modulus size limits in bits.
///
/// All other public-key checks still apply. Allowing a smaller minimum can admit insecure
/// keys and is intended for testing or compatibility with legacy systems.
///
/// For encoded keys outside the default limits, decode the components with the `pkcs1`
/// crate and pass them to this constructor explicitly.
///
/// # Errors
/// Returns [`Error::InvalidArguments`] for an empty range, [`Error::ModulusTooSmall`] or
/// [`Error::ModulusTooLarge`] for a modulus outside the range, or an error if the modulus
/// or public exponent is invalid.
pub fn new_with_size_limits(
n: BoxedUint,
e: BoxedUint,
size_range_bits: RangeInclusive<usize>,
) -> Result<Self> {
if size_range_bits.is_empty() {
return Err(Error::InvalidArguments);
}
if (n.bits_vartime() as usize) < *size_range_bits.start() {
return Err(Error::ModulusTooSmall);
}
check_public_with_max_size(&n, &e, Some(*size_range_bits.end()))?;
let n_odd = Odd::new(n.clone())
.into_option()
.ok_or(Error::InvalidModulus)?;
let n_params = BoxedMontyParams::new(n_odd);
let n = NonZero::new(n).expect("checked above");
Ok(Self { n, e, n_params })
}
/// Create a new public key with the default minimum modulus size and a custom maximum.
#[deprecated(since = "0.10.0", note = "please use `new_with_size_limits` instead")]
#[allow(clippy::missing_errors_doc, reason = "TODO")]
pub fn new_with_max_size(n: BoxedUint, e: BoxedUint, max_size: usize) -> Result<Self> {
Self::new_with_size_limits(n, e, Self::MIN_SIZE..=max_size)
}
/// Create a new public key, bypassing checks around the modulus and public
/// exponent size.
///
/// This method is not recommended, and only intended for unusual use cases.
/// Most applications should use [`RsaPublicKey::new`] or
/// [`RsaPublicKey::new_with_size_limits`] instead.
#[must_use]
pub fn new_unchecked(n: BoxedUint, e: BoxedUint) -> Self {
let n_odd = Odd::new(n.clone()).expect("n must be odd");
let n_params = BoxedMontyParams::new(n_odd);
let n = NonZero::new(n).expect("odd numbers are non zero");
Self { n, e, n_params }
}
}
impl Eq for RsaPublicKey {}
impl PartialEq for RsaPublicKey {
#[inline]
fn eq(&self, other: &RsaPublicKey) -> bool {
self.n == other.n && self.e == other.e
}
}
impl From<RsaPrivateKey> for RsaPublicKey {
fn from(private_key: RsaPrivateKey) -> Self {
(&private_key).into()
}
}
impl From<&RsaPrivateKey> for RsaPublicKey {
fn from(private_key: &RsaPrivateKey) -> Self {
let n = PublicKeyParts::n(private_key);
let e = PublicKeyParts::e(private_key);
let n_params = PublicKeyParts::n_params(private_key);
RsaPublicKey {
n: n.clone(),
e: e.clone(),
n_params: n_params.clone(),
}
}
}
impl Hash for RsaPublicKey {
fn hash<H: Hasher>(&self, state: &mut H) {
// Domain separator for RSA private keys
state.write(b"RsaPublicKey");
// TODO(tarcieri): to match the `PartialEq` impl we should strip leading zeros
Hash::hash(&self.n.as_limbs(), state);
Hash::hash(&self.e.as_limbs(), state);
}
}
impl PublicKeyParts for RsaPublicKey {
fn n(&self) -> &NonZero<BoxedUint> {
&self.n
}
fn e(&self) -> &BoxedUint {
&self.e
}
fn n_params(&self) -> &BoxedMontyParams {
&self.n_params
}
}
#[cfg(feature = "serde")]
impl Serialize for RsaPublicKey {
fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let der = self.to_public_key_der().map_err(ser::Error::custom)?;
serdect::slice::serialize_hex_lower_or_bin(&der, serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RsaPublicKey {
fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
Self::from_public_key_der(&der_bytes).map_err(de::Error::custom)
}
}
/// Check that the public key is well formed and has an exponent within acceptable bounds.
#[inline]
pub(crate) fn check_public(public_key: &impl PublicKeyParts) -> Result<()> {
check_public_with_max_size(public_key.n(), public_key.e(), None)
}
/// Check that the public key is well formed and has an exponent within acceptable bounds.
#[inline]
fn check_public_with_max_size(n: &BoxedUint, e: &BoxedUint, max_size: Option<usize>) -> Result<()> {
if let Some(max_size) = max_size {
if n.bits_vartime() as usize > max_size {
return Err(Error::ModulusTooLarge);
}
}
check_public_skip_exponent_size(n, e)?;
if e < &BoxedUint::from(RsaPublicKey::MIN_PUB_EXPONENT) {
return Err(Error::PublicExponentTooSmall);
}
if e > &BoxedUint::from(RsaPublicKey::MAX_PUB_EXPONENT) {
return Err(Error::PublicExponentTooLarge);
}
Ok(())
}
/// Check that the public key is well formed, skipping exponent size bounds checks.
///
/// This is used internally by both public validation functions and hazmat APIs.
#[inline]
pub(crate) fn check_public_skip_exponent_size(n: &BoxedUint, e: &BoxedUint) -> Result<()> {
if e >= n || n.is_even().into() || n.is_zero().into() {
return Err(Error::InvalidModulus);
}
if e.is_even().into() {
return Err(Error::InvalidExponent);
}
// Skip exponent size bounds checks
Ok(())
}