| // Copyright 2015-2021 Brian Smith. |
| // |
| // Permission to use, copy, modify, and/or distribute this software for any |
| // purpose with or without fee is hereby granted, provided that the above |
| // copyright notice and this permission notice appear in all copies. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
| // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
| // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
| use super::{PublicExponent, PublicModulus, N, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN}; |
| use crate::{ |
| arithmetic::bigint, |
| bits, cpu, error, |
| io::{self, der, der_writer}, |
| limb::LIMB_BYTES, |
| }; |
| use alloc::boxed::Box; |
| |
| /// An RSA Public Key. |
| #[derive(Clone)] |
| pub struct PublicKey { |
| n: PublicModulus, |
| e: PublicExponent, |
| serialized: Box<[u8]>, |
| } |
| |
| derive_debug_self_as_ref_hex_bytes!(PublicKey); |
| |
| impl PublicKey { |
| pub(super) fn from_modulus_and_exponent( |
| n: untrusted::Input, |
| e: untrusted::Input, |
| n_min_bits: bits::BitLength, |
| n_max_bits: bits::BitLength, |
| e_min_value: PublicExponent, |
| cpu_features: cpu::Features, |
| ) -> Result<Self, error::KeyRejected> { |
| let n_bytes = n; |
| let e_bytes = e; |
| |
| // This is an incomplete implementation of NIST SP800-56Br1 Section |
| // 6.4.2.2, "Partial Public-Key Validation for RSA." That spec defers |
| // to NIST SP800-89 Section 5.3.3, "(Explicit) Partial Public Key |
| // Validation for RSA," "with the caveat that the length of the modulus |
| // shall be a length that is specified in this Recommendation." In |
| // SP800-89, two different sets of steps are given, one set numbered, |
| // and one set lettered. TODO: Document this in the end-user |
| // documentation for RSA keys. |
| |
| let n = PublicModulus::from_be_bytes(n, n_min_bits..=n_max_bits, cpu_features)?; |
| |
| let e = PublicExponent::from_be_bytes(e, e_min_value)?; |
| |
| // If `n` is less than `e` then somebody has probably accidentally swapped |
| // them. The largest acceptable `e` is smaller than the smallest acceptable |
| // `n`, so no additional checks need to be done. |
| |
| // XXX: Steps 4 & 5 / Steps d, e, & f are not implemented. This is also the |
| // case in most other commonly-used crypto libraries. |
| |
| // TODO: Remove this re-parsing, and stop allocating this here. |
| // Instead we should serialize on demand without allocation, from |
| // `Modulus::be_bytes()` and `Exponent::be_bytes()`. |
| let n_bytes = io::Positive::from_be_bytes(n_bytes) |
| .map_err(|_: error::Unspecified| error::KeyRejected::unexpected_error())?; |
| let e_bytes = io::Positive::from_be_bytes(e_bytes) |
| .map_err(|_: error::Unspecified| error::KeyRejected::unexpected_error())?; |
| let serialized = der_writer::write_all(der::Tag::Sequence, &|output| { |
| der_writer::write_positive_integer(output, &n_bytes); |
| der_writer::write_positive_integer(output, &e_bytes); |
| }); |
| |
| Ok(Self { n, e, serialized }) |
| } |
| |
| /// The length, in bytes, of the public modulus. |
| /// |
| /// The modulus length is rounded up to a whole number of bytes if its |
| /// bit length isn't a multiple of 8. |
| pub fn modulus_len(&self) -> usize { |
| self.n().len_bits().as_usize_bytes_rounded_up() |
| } |
| |
| /// The public modulus. |
| #[inline] |
| pub(super) fn n(&self) -> &PublicModulus { |
| &self.n |
| } |
| |
| /// The public exponent. |
| #[inline] |
| pub(super) fn e(&self) -> PublicExponent { |
| self.e |
| } |
| |
| /// Calculates base**e (mod n), filling the first part of `out_buffer` with |
| /// the result. |
| /// |
| /// This is constant-time with respect to the value in `base` (only). |
| /// |
| /// The result will be a slice of the encoded bytes of the result within |
| /// `out_buffer`, if successful. |
| pub(super) fn exponentiate<'out>( |
| &self, |
| base: untrusted::Input, |
| out_buffer: &'out mut [u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN], |
| ) -> Result<&'out [u8], error::Unspecified> { |
| let n = &self.n.value(); |
| |
| // The encoded value of the base must be the same length as the modulus, |
| // in bytes. |
| if base.len() != self.n.len_bits().as_usize_bytes_rounded_up() { |
| return Err(error::Unspecified); |
| } |
| |
| // RFC 8017 Section 5.2.2: RSAVP1. |
| |
| // Step 1. |
| let s = bigint::Elem::from_be_bytes_padded(base, n)?; |
| if s.is_zero() { |
| return Err(error::Unspecified); |
| } |
| |
| // Step 2. |
| let m = self.exponentiate_elem(s); |
| |
| // Step 3. |
| Ok(fill_be_bytes_n(m, self.n.len_bits(), out_buffer)) |
| } |
| |
| /// Calculates base**e (mod n). |
| /// |
| /// This is constant-time with respect to `base` only. |
| pub(super) fn exponentiate_elem(&self, base: bigint::Elem<N>) -> bigint::Elem<N> { |
| let n = self.n.value(); |
| |
| let base = bigint::elem_mul(n.oneRR().as_ref(), base, n); |
| // During RSA public key operations the exponent is almost always either |
| // 65537 (0b10000000000000001) or 3 (0b11), both of which have a Hamming |
| // weight of 2. The maximum bit length and maximum Hamming weight of the |
| // exponent is bounded by the value of `PublicExponent::MAX`. |
| bigint::elem_exp_vartime(base, self.e.value(), &n.as_partial()).into_unencoded(n) |
| } |
| } |
| |
| // XXX: Refactor `signature::KeyPair` to get rid of this. |
| impl AsRef<[u8]> for PublicKey { |
| fn as_ref(&self) -> &[u8] { |
| &self.serialized |
| } |
| } |
| |
| /// Returns the big-endian representation of `elem` that is |
| /// the same length as the minimal-length big-endian representation of |
| /// the modulus `n`. |
| /// |
| /// `n_bits` must be the bit length of the public modulus `n`. |
| fn fill_be_bytes_n( |
| elem: bigint::Elem<N>, |
| n_bits: bits::BitLength, |
| out: &mut [u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN], |
| ) -> &[u8] { |
| let n_bytes = n_bits.as_usize_bytes_rounded_up(); |
| let n_bytes_padded = ((n_bytes + (LIMB_BYTES - 1)) / LIMB_BYTES) * LIMB_BYTES; |
| let out = &mut out[..n_bytes_padded]; |
| elem.fill_be_bytes(out); |
| let (padding, out) = out.split_at(n_bytes_padded - n_bytes); |
| assert!(padding.iter().all(|&b| b == 0)); |
| out |
| } |