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 from_be_bytes( input: untrusted::Input, min_value: Self, ) -> Result<Self, error::KeyRejected>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. be_bytes(&self) -> impl ExactSizeIterator<Item = u8> + Clone + '_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 value(self) -> NonZeroU6486 pub(super) fn value(self) -> NonZeroU64 { 87 self.0 88 } 89 } 90 91 #[cfg(test)] 92 mod tests { 93 use super::*; 94 95 #[test] test_public_exponent_constants()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