1 | use crate::error; |
2 | use crate::polyfill::{unwrap_const, ArrayFlatMap, LeadingZerosStripped}; |
3 | use core::num::NonZeroU64; |
4 | |
5 | /// The exponent `e` of an RSA public key. |
6 | #[derive (Clone, Copy)] |
7 | pub struct PublicExponent(NonZeroU64); |
8 | |
9 | impl PublicExponent { |
10 | #[cfg (test)] |
11 | const ALL_CONSTANTS: [Self; 3] = [Self::_3, Self::_65537, Self::MAX]; |
12 | |
13 | pub(super) const _3: Self = Self(unwrap_const(NonZeroU64::new(3))); |
14 | pub(super) const _65537: Self = Self(unwrap_const(NonZeroU64::new(65537))); |
15 | |
16 | // This limit was chosen to bound the performance of the simple |
17 | // exponentiation-by-squaring implementation in `elem_exp_vartime`. In |
18 | // particular, it helps mitigate theoretical resource exhaustion attacks. 33 |
19 | // bits was chosen as the limit based on the recommendations in [1] and |
20 | // [2]. Windows CryptoAPI (at least older versions) doesn't support values |
21 | // larger than 32 bits [3], so it is unlikely that exponents larger than 32 |
22 | // bits are being used for anything Windows commonly does. |
23 | // |
24 | // [1] https://www.imperialviolet.org/2012/03/16/rsae.html |
25 | // [2] https://www.imperialviolet.org/2012/03/17/rsados.html |
26 | // [3] https://msdn.microsoft.com/en-us/library/aa387685(VS.85).aspx |
27 | const MAX: Self = Self(unwrap_const(NonZeroU64::new((1u64 << 33) - 1))); |
28 | |
29 | pub(super) fn from_be_bytes( |
30 | input: untrusted::Input, |
31 | min_value: Self, |
32 | ) -> Result<Self, error::KeyRejected> { |
33 | // See `PublicKey::from_modulus_and_exponent` for background on the step |
34 | // numbering. |
35 | |
36 | if input.len() > 5 { |
37 | return Err(error::KeyRejected::too_large()); |
38 | } |
39 | let value = input.read_all(error::KeyRejected::invalid_encoding(), |input| { |
40 | // The exponent can't be zero and it can't be prefixed with |
41 | // zero-valued bytes. |
42 | if input.peek(0) { |
43 | return Err(error::KeyRejected::invalid_encoding()); |
44 | } |
45 | let mut value = 0u64; |
46 | loop { |
47 | let byte = input |
48 | .read_byte() |
49 | .map_err(|untrusted::EndOfInput| error::KeyRejected::invalid_encoding())?; |
50 | value = (value << 8) | u64::from(byte); |
51 | if input.at_end() { |
52 | return Ok(value); |
53 | } |
54 | } |
55 | })?; |
56 | |
57 | // Step 2 / Step b. NIST SP800-89 defers to FIPS 186-3, which requires |
58 | // `e >= 65537`. We enforce this when signing, but are more flexible in |
59 | // verification, for compatibility. Only small public exponents are |
60 | // supported. |
61 | let value = NonZeroU64::new(value).ok_or_else(error::KeyRejected::too_small)?; |
62 | if value < min_value.0 { |
63 | return Err(error::KeyRejected::too_small()); |
64 | } |
65 | if value > Self::MAX.0 { |
66 | return Err(error::KeyRejected::too_large()); |
67 | } |
68 | |
69 | // Step 3 / Step c. |
70 | if value.get() & 1 != 1 { |
71 | return Err(error::KeyRejected::invalid_component()); |
72 | } |
73 | |
74 | Ok(Self(value)) |
75 | } |
76 | |
77 | /// The big-endian encoding of the exponent. |
78 | /// |
79 | /// There are no leading zeros. |
80 | pub fn be_bytes(&self) -> impl ExactSizeIterator<Item = u8> + Clone + '_ { |
81 | // The `unwrap()` won't fail as `self.0` is only a few bytes long. |
82 | let bytes = ArrayFlatMap::new(core::iter::once(self.0.get()), u64::to_be_bytes).unwrap(); |
83 | LeadingZerosStripped::new(bytes) |
84 | } |
85 | |
86 | pub(super) fn value(self) -> NonZeroU64 { |
87 | self.0 |
88 | } |
89 | } |
90 | |
91 | #[cfg (test)] |
92 | mod tests { |
93 | use super::*; |
94 | |
95 | #[test ] |
96 | fn test_public_exponent_constants() { |
97 | for value in PublicExponent::ALL_CONSTANTS.iter() { |
98 | let value: u64 = value.0.into(); |
99 | assert_eq!(value & 1, 1); |
100 | assert!(value >= PublicExponent::_3.0.into()); // The absolute minimum. |
101 | assert!(value <= PublicExponent::MAX.0.into()); |
102 | } |
103 | } |
104 | } |
105 | |