use crate::error; use crate::polyfill::{unwrap_const, ArrayFlatMap, LeadingZerosStripped}; use core::num::NonZeroU64; /// The exponent `e` of an RSA public key. #[derive(Clone, Copy)] pub struct PublicExponent(NonZeroU64); impl PublicExponent { #[cfg(test)] const ALL_CONSTANTS: [Self; 3] = [Self::_3, Self::_65537, Self::MAX]; pub(super) const _3: Self = Self(unwrap_const(NonZeroU64::new(3))); pub(super) const _65537: Self = Self(unwrap_const(NonZeroU64::new(65537))); // This limit was chosen to bound the performance of the simple // exponentiation-by-squaring implementation in `elem_exp_vartime`. In // particular, it helps mitigate theoretical resource exhaustion attacks. 33 // bits was chosen as the limit based on the recommendations in [1] and // [2]. Windows CryptoAPI (at least older versions) doesn't support values // larger than 32 bits [3], so it is unlikely that exponents larger than 32 // bits are being used for anything Windows commonly does. // // [1] https://www.imperialviolet.org/2012/03/16/rsae.html // [2] https://www.imperialviolet.org/2012/03/17/rsados.html // [3] https://msdn.microsoft.com/en-us/library/aa387685(VS.85).aspx const MAX: Self = Self(unwrap_const(NonZeroU64::new((1u64 << 33) - 1))); pub(super) fn from_be_bytes( input: untrusted::Input, min_value: Self, ) -> Result { // See `PublicKey::from_modulus_and_exponent` for background on the step // numbering. if input.len() > 5 { return Err(error::KeyRejected::too_large()); } let value = input.read_all(error::KeyRejected::invalid_encoding(), |input| { // The exponent can't be zero and it can't be prefixed with // zero-valued bytes. if input.peek(0) { return Err(error::KeyRejected::invalid_encoding()); } let mut value = 0u64; loop { let byte = input .read_byte() .map_err(|untrusted::EndOfInput| error::KeyRejected::invalid_encoding())?; value = (value << 8) | u64::from(byte); if input.at_end() { return Ok(value); } } })?; // Step 2 / Step b. NIST SP800-89 defers to FIPS 186-3, which requires // `e >= 65537`. We enforce this when signing, but are more flexible in // verification, for compatibility. Only small public exponents are // supported. let value = NonZeroU64::new(value).ok_or_else(error::KeyRejected::too_small)?; if value < min_value.0 { return Err(error::KeyRejected::too_small()); } if value > Self::MAX.0 { return Err(error::KeyRejected::too_large()); } // Step 3 / Step c. if value.get() & 1 != 1 { return Err(error::KeyRejected::invalid_component()); } Ok(Self(value)) } /// The big-endian encoding of the exponent. /// /// There are no leading zeros. pub fn be_bytes(&self) -> impl ExactSizeIterator + Clone + '_ { // The `unwrap()` won't fail as `self.0` is only a few bytes long. let bytes = ArrayFlatMap::new(core::iter::once(self.0.get()), u64::to_be_bytes).unwrap(); LeadingZerosStripped::new(bytes) } pub(super) fn value(self) -> NonZeroU64 { self.0 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_public_exponent_constants() { for value in PublicExponent::ALL_CONSTANTS.iter() { let value: u64 = value.0.into(); assert_eq!(value & 1, 1); assert!(value >= PublicExponent::_3.0.into()); // The absolute minimum. assert!(value <= PublicExponent::MAX.0.into()); } } }