RSA: Flatten API by removing public and keypair submodules.

When looking at how this would generlaize to the other public key
cryptosystems (ECDSA, ED25519, etc.), I think having fewer submodules
involved makes more sense.
This commit is contained in:
Brian Smith 2021-09-28 11:44:07 -07:00
parent 88c281e3ea
commit 1879c0555d
13 changed files with 94 additions and 103 deletions

View File

@ -60,11 +60,17 @@ enum N {}
unsafe impl bigint::PublicModulus for N {}
mod keypair;
mod keypair_components;
pub mod public;
mod public_exponent;
mod public_key;
mod public_key_components;
mod public_modulus;
pub(crate) mod verification;
pub(crate) mod signing;
pub use self::keypair_components::KeyPairComponents;
pub use self::{
keypair::KeyPair, keypair_components::KeyPairComponents, public_exponent::PublicExponent,
public_key::PublicKey, public_key_components::PublicKeyComponents,
public_modulus::PublicModulus,
};

View File

@ -12,7 +12,9 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{padding::RsaEncoding, public, KeyPairComponents, N};
use super::{
padding::RsaEncoding, KeyPairComponents, PublicExponent, PublicKey, PublicKeyComponents, N,
};
/// RSA PKCS#1 1.5 signatures.
use crate::{
@ -23,22 +25,22 @@ use crate::{
bits, cpu, digest,
error::{self, KeyRejected},
io::der,
pkcs8, rand, rsa, signature,
pkcs8, rand, signature,
};
/// An RSA key pair, used for signing.
pub struct RsaKeyPair {
pub struct KeyPair {
p: PrivatePrime<P>,
q: PrivatePrime<Q>,
qInv: bigint::Elem<P, R>,
qq: bigint::Modulus<QQ>,
q_mod_n: bigint::Elem<N, R>,
public: public::Key,
public: PublicKey,
}
derive_debug_via_field!(RsaKeyPair, stringify!(RsaKeyPair), public);
derive_debug_via_field!(KeyPair, stringify!(RsaKeyPair), public);
impl RsaKeyPair {
impl KeyPair {
/// Parses an unencrypted PKCS#8-encoded RSA private key.
///
/// This will generate a 2048-bit RSA private key of the correct form using
@ -156,7 +158,7 @@ impl RsaKeyPair {
let qInv = nonnegative_integer(input)?;
let components = KeyPairComponents {
public_key: super::public::Components { n, e },
public_key: PublicKeyComponents { n, e },
d,
p,
q,
@ -221,7 +223,7 @@ impl RsaKeyPair {
Private: AsRef<[u8]>,
{
let components = KeyPairComponents {
public_key: public::Components {
public_key: PublicKeyComponents {
n: components.public_key.n.as_ref(),
e: components.public_key.e.as_ref(),
},
@ -291,12 +293,12 @@ impl RsaKeyPair {
// Step 1.c. We validate e >= 65537.
let n = untrusted::Input::from(public_key.n);
let e = untrusted::Input::from(public_key.e);
let public_key = public::Key::from_modulus_and_exponent(
let public_key = PublicKey::from_modulus_and_exponent(
n,
e,
bits::BitLength::from_usize_bits(2048),
super::PRIVATE_KEY_PUBLIC_MODULUS_MAX_BITS,
public::Exponent::_65537,
PublicExponent::_65537,
cpu_features,
)?;
@ -433,7 +435,7 @@ impl RsaKeyPair {
}
/// Returns a reference to the public key.
pub fn public(&self) -> &public::Key {
pub fn public(&self) -> &PublicKey {
&self.public
}
@ -447,8 +449,8 @@ impl RsaKeyPair {
}
}
impl signature::KeyPair for RsaKeyPair {
type PublicKey = rsa::public::Key;
impl signature::KeyPair for KeyPair {
type PublicKey = PublicKey;
fn public_key(&self) -> &Self::PublicKey {
self.public()
@ -542,7 +544,7 @@ unsafe impl bigint::SlightlySmallerModulus<P> for Q {}
unsafe impl bigint::SmallerModulus<QQ> for Q {}
unsafe impl bigint::NotMuchSmallerModulus<QQ> for Q {}
impl RsaKeyPair {
impl KeyPair {
/// Sign `msg`. `msg` is digested using the digest algorithm from
/// `padding_alg` and the digest is then padded using the padding algorithm
/// from `padding_alg`. The signature it written into `signature`;

View File

@ -1,10 +1,10 @@
use super::public;
use super::PublicKeyComponents;
/// RSA key pair components.
#[derive(Clone, Copy)]
pub struct KeyPairComponents<Public, Private = Public> {
/// The public key components.
pub public_key: super::public::Components<Public>,
pub public_key: PublicKeyComponents<Public>,
/// The private exponent.
pub d: Private,
@ -27,11 +27,11 @@ pub struct KeyPairComponents<Public, Private = Public> {
impl<Public, Private> core::fmt::Debug for KeyPairComponents<Public, Private>
where
public::Components<Public>: core::fmt::Debug,
PublicKeyComponents<Public>: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
// Non-public components are intentionally skipped
f.debug_struct("Components")
f.debug_struct("KeyPairComponents")
.field("public_key", &self.public_key)
.finish()
}

View File

@ -148,7 +148,7 @@ macro_rules! rsa_pkcs1_padding {
// don't currently have. But, it's a bad idea to use SHA-1 anyway, so perhaps
// we just won't ever expose it.
rsa_pkcs1_padding!(
pub(in super) RSA_PKCS1_SHA1_FOR_LEGACY_USE_ONLY,
pub(super) RSA_PKCS1_SHA1_FOR_LEGACY_USE_ONLY,
&digest::SHA1_FOR_LEGACY_USE_ONLY,
&SHA1_PKCS1_DIGESTINFO_PREFIX,
"PKCS#1 1.5 padding using SHA-1 for RSA signatures."

View File

@ -1,22 +0,0 @@
// Copyright 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.
//! RSA public keys.
mod components;
mod exponent;
mod key;
mod modulus;
pub use {components::Components, exponent::Exponent, key::Key, modulus::Modulus};

View File

@ -4,16 +4,16 @@ use core::num::NonZeroU64;
/// The exponent `e` of an RSA public key.
#[derive(Clone, Copy, Debug)]
pub struct Exponent(NonZeroU64);
pub struct PublicExponent(NonZeroU64);
impl Exponent {
impl PublicExponent {
#[cfg(test)]
const ALL_CONSTANTS: [Self; 3] = [Self::_3, Self::_65537, Self::MAX];
// TODO: Use `NonZeroU64::new(...).unwrap()` when `feature(const_panic)` is
// stable.
pub(in super::super) const _3: Self = Self(unsafe { NonZeroU64::new_unchecked(3) });
pub(in super::super) const _65537: Self = Self(unsafe { NonZeroU64::new_unchecked(65537) });
pub(super) const _3: Self = Self(unsafe { NonZeroU64::new_unchecked(3) });
pub(super) const _65537: Self = Self(unsafe { NonZeroU64::new_unchecked(65537) });
// This limit was chosen to bound the performance of the simple
// exponentiation-by-squaring implementation in `elem_exp_vartime`. In
@ -35,7 +35,7 @@ impl Exponent {
input: untrusted::Input,
min_value: Self,
) -> Result<Self, error::KeyRejected> {
// See `public::Key::from_modulus_and_exponent` for background on the step
// See `PublicKey::from_modulus_and_exponent` for background on the step
// numbering.
if input.len() > 5 {
@ -91,7 +91,7 @@ impl Exponent {
LeadingZerosStripped::new(bytes)
}
pub(in super::super) fn value(self) -> NonZeroU64 {
pub(super) fn value(self) -> NonZeroU64 {
self.0
}
}
@ -103,19 +103,21 @@ mod tests {
#[test]
fn test_public_exponent_debug() {
let exponent =
Exponent::from_be_bytes(untrusted::Input::from(&[0x1, 0x00, 0x01]), Exponent::_65537)
.unwrap();
assert_eq!("Exponent(65537)", format!("{:?}", exponent));
let exponent = PublicExponent::from_be_bytes(
untrusted::Input::from(&[0x1, 0x00, 0x01]),
PublicExponent::_65537,
)
.unwrap();
assert_eq!("PublicExponent(65537)", format!("{:?}", exponent));
}
#[test]
fn test_public_exponent_constants() {
for value in Exponent::ALL_CONSTANTS.iter() {
for value in PublicExponent::ALL_CONSTANTS.iter() {
let value: u64 = value.0.into();
assert_eq!(value & 1, 1);
assert!(value >= Exponent::_3.0.into()); // The absolute minimum.
assert!(value <= Exponent::MAX.0.into());
assert!(value >= PublicExponent::_3.0.into()); // The absolute minimum.
assert!(value <= PublicExponent::MAX.0.into());
}
}
}

View File

@ -12,10 +12,7 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use super::{
super::{N, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN},
Exponent, Modulus,
};
use super::{PublicExponent, PublicModulus, N, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN};
use crate::{
arithmetic::bigint,
bits, cpu, error,
@ -26,22 +23,22 @@ use alloc::boxed::Box;
/// An RSA Public Key.
#[derive(Clone)]
pub struct Key {
n: Modulus,
e: Exponent,
pub struct PublicKey {
n: PublicModulus,
e: PublicExponent,
serialized: Box<[u8]>,
cpu_features: cpu::Features,
}
derive_debug_self_as_ref_hex_bytes!(Key);
derive_debug_self_as_ref_hex_bytes!(PublicKey);
impl Key {
pub(in super::super) fn from_modulus_and_exponent(
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: Exponent,
e_min_value: PublicExponent,
cpu_features: cpu::Features,
) -> Result<Self, error::KeyRejected> {
let n_bytes = n;
@ -56,9 +53,9 @@ impl Key {
// and one set lettered. TODO: Document this in the end-user
// documentation for RSA keys.
let n = Modulus::from_be_bytes(n, n_min_bits..=n_max_bits, cpu_features)?;
let n = PublicModulus::from_be_bytes(n, n_min_bits..=n_max_bits, cpu_features)?;
let e = Exponent::from_be_bytes(e, e_min_value)?;
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
@ -89,13 +86,13 @@ impl Key {
/// The public modulus.
#[inline]
pub fn n(&self) -> &Modulus {
pub fn n(&self) -> &PublicModulus {
&self.n
}
/// The public exponent.
#[inline]
pub fn e(&self) -> Exponent {
pub fn e(&self) -> PublicExponent {
self.e
}
@ -106,7 +103,7 @@ impl Key {
///
/// The result will be a slice of the encoded bytes of the result within
/// `out_buffer`, if successful.
pub(in super::super) fn exponentiate<'out>(
pub(super) fn exponentiate<'out>(
&self,
base: untrusted::Input,
out_buffer: &'out mut [u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN],
@ -137,20 +134,20 @@ impl Key {
/// Calculates base**e (mod n).
///
/// This is constant-time with respect to `base` only.
pub(in super::super) fn exponentiate_elem(&self, base: bigint::Elem<N>) -> bigint::Elem<N> {
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 `public::Exponent::MAX`.
// 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 Key {
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
&self.serialized
}

View File

@ -16,7 +16,7 @@
///
/// `B` must implement `AsRef<[u8]>` like `&[u8]` or `Vec<u8>`.
#[derive(Clone, Copy)]
pub struct Components<B> {
pub struct PublicKeyComponents<B> {
/// The public modulus, encoded in big-endian bytes without leading zeros.
pub n: B,
@ -24,12 +24,12 @@ pub struct Components<B> {
pub e: B,
}
impl<B> core::fmt::Debug for Components<B>
impl<B> core::fmt::Debug for PublicKeyComponents<B>
where
B: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
f.debug_struct("Components")
f.debug_struct("PublicKeyComponents")
.field("n", &self.n)
.field("e", &self.e)
.finish()

View File

@ -3,24 +3,24 @@ use core::ops::RangeInclusive;
/// The modulus (n) of an RSA public key.
#[derive(Clone)]
pub struct Modulus {
pub struct PublicModulus {
value: bigint::Modulus<N>,
bits: bits::BitLength,
}
impl core::fmt::Debug for Modulus {
impl core::fmt::Debug for PublicModulus {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> {
self.value.fmt(fmt)
}
}
impl Modulus {
impl PublicModulus {
pub(super) fn from_be_bytes(
n: untrusted::Input,
allowed_bit_lengths: RangeInclusive<bits::BitLength>,
cpu_features: cpu::Features,
) -> Result<Self, error::KeyRejected> {
// See `public::Key::from_modulus_and_exponent` for background on the step
// See `PublicKey::from_modulus_and_exponent` for background on the step
// numbering.
let min_bits = *allowed_bit_lengths.start();
@ -64,7 +64,7 @@ impl Modulus {
self.bits
}
pub(in super::super) fn value(&self) -> &bigint::Modulus<N> {
pub(super) fn value(&self) -> &bigint::Modulus<N> {
&self.value
}
}

View File

@ -14,7 +14,9 @@
//! Verification of RSA signatures.
use super::{parse_public_key, public, RsaParameters, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN};
use super::{
parse_public_key, PublicExponent, PublicKey, RsaParameters, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN,
};
use crate::{bits, cpu, digest, error, sealed, signature};
impl signature::VerificationAlgorithm for RsaParameters {
@ -142,9 +144,9 @@ rsa_params!(
`ring::signature`'s module-level documentation for more details."
);
pub use super::public::Components as RsaPublicKeyComponents;
pub use super::PublicKeyComponents as RsaPublicKeyComponents;
impl<B> super::public::Components<B>
impl<B> super::PublicKeyComponents<B>
where
B: AsRef<[u8]>,
{
@ -199,12 +201,12 @@ pub(crate) fn verify_rsa_(
// exponent value is 2**16 + 1, but it isn't clear if this is just for
// signing or also for verification. We support exponents of 3 and larger
// for compatibility with other commonly-used crypto libraries.
let key = public::Key::from_modulus_and_exponent(
let key = PublicKey::from_modulus_and_exponent(
n,
e,
params.min_bits,
max_bits,
public::Exponent::_3,
PublicExponent::_3,
cpu::features(),
)?;

View File

@ -191,16 +191,16 @@
//! ```
//!
//! ```
//! use ring::{rand, signature};
//! use ring::{rand, rsa, signature};
//!
//! # #[cfg(feature = "std")]
//! fn sign_and_verify_rsa(private_key_path: &std::path::Path,
//! public_key_path: &std::path::Path)
//! -> Result<(), MyError> {
//! // Create an `RsaKeyPair` from the DER-encoded bytes. This example uses
//! // Create an RSA keypair from the DER-encoded bytes. This example uses
//! // a 2048-bit key, but larger keys are also supported.
//! let private_key_der = read_file(private_key_path)?;
//! let key_pair = signature::RsaKeyPair::from_der(&private_key_der)
//! let key_pair = rsa::KeyPair::from_der(&private_key_der)
//! .map_err(|_| MyError::BadPrivateKey)?;
//!
//! // Sign the message "hello, world", using PKCS#1 v1.5 padding and the
@ -282,7 +282,6 @@ pub use crate::rsa::{
RsaEncoding, RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, RSA_PSS_SHA256,
RSA_PSS_SHA384, RSA_PSS_SHA512,
},
signing::RsaKeyPair,
verification::{
RsaPublicKeyComponents, RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
@ -294,6 +293,11 @@ pub use crate::rsa::{
RsaParameters,
};
/// An RSA key pair, used for signing.
#[cfg(feature = "alloc")]
#[deprecated = "Use `rsa::KeyPair`"]
pub type RsaKeyPair = crate::rsa::KeyPair;
/// A public key signature returned from a signing operation.
#[derive(Clone, Copy)]
pub struct Signature {

View File

@ -1 +1 @@
Key("3082010a0282010100c8a78500a5a250db8ed36c85b8dcf83c4be1953114faaac7616e0ea24922fa6b7ab01f85582c815cc3bdeb5ed46762bc536accaa8b72705b00cef316b2ec508fb9697241b9e34238419cccf7339eeb8b062147af4f5932f613d9bc0ae70bf6d56d4432e83e13767587531bfa9dd56531741244be75e8bc9226b9fa44b4b8a101358d7e8bb75d0c724a4f11ece77776263faefe79612eb1d71646e77e8982866be1400eafc3580d3139b41aaa7380187372f22e35bd55b288496165c881ed154d5811245c52d56cc09d4916d4f2a50bcf5ae0a2637f4cfa6bf9daafc113dba8383b6dd7da6dd8db22d8510a8d3115983308909a1a0332517aa55e896e154249b30203010001")
PublicKey("3082010a0282010100c8a78500a5a250db8ed36c85b8dcf83c4be1953114faaac7616e0ea24922fa6b7ab01f85582c815cc3bdeb5ed46762bc536accaa8b72705b00cef316b2ec508fb9697241b9e34238419cccf7339eeb8b062147af4f5932f613d9bc0ae70bf6d56d4432e83e13767587531bfa9dd56531741244be75e8bc9226b9fa44b4b8a101358d7e8bb75d0c724a4f11ece77776263faefe79612eb1d71646e77e8982866be1400eafc3580d3139b41aaa7380187372f22e35bd55b288496165c881ed154d5811245c52d56cc09d4916d4f2a50bcf5ae0a2637f4cfa6bf9daafc113dba8383b6dd7da6dd8db22d8510a8d3115983308909a1a0332517aa55e896e154249b30203010001")

View File

@ -39,7 +39,7 @@ fn rsa_from_pkcs8_test() {
let input = test_case.consume_bytes("Input");
let error = test_case.consume_optional_string("Error");
match (signature::RsaKeyPair::from_pkcs8(&input), error) {
match (rsa::KeyPair::from_pkcs8(&input), error) {
(Ok(_), None) => {}
(Err(e), None) => panic!("Failed with error \"{}\", but expected to succeed", e),
(Ok(_), Some(e)) => panic!("Succeeded, but expected error \"{}\"", e),
@ -73,7 +73,7 @@ fn test_signature_rsa_pkcs1_sign() {
let expected = test_case.consume_bytes("Sig");
let result = test_case.consume_string("Result");
let key_pair = signature::RsaKeyPair::from_der(&private_key);
let key_pair = rsa::KeyPair::from_der(&private_key);
if result == "Fail-Invalid-Key" {
assert!(key_pair.is_err());
return Ok(());
@ -111,7 +111,7 @@ fn test_signature_rsa_pss_sign() {
let result = test_case.consume_string("Result");
let private_key = test_case.consume_bytes("Key");
let key_pair = signature::RsaKeyPair::from_der(&private_key);
let key_pair = rsa::KeyPair::from_der(&private_key);
if key_pair.is_err() && result == "Fail-Invalid-Key" {
return Ok(());
}
@ -142,7 +142,7 @@ fn test_signature_rsa_pkcs1_sign_output_buffer_len() {
const PRIVATE_KEY_DER: &[u8] =
include_bytes!("../src/rsa/signature_rsa_example_private_key.der");
let key_pair = signature::RsaKeyPair::from_der(PRIVATE_KEY_DER).unwrap();
let key_pair = rsa::KeyPair::from_der(PRIVATE_KEY_DER).unwrap();
// The output buffer is one byte too short.
let mut signature = vec![0; key_pair.public().n().len_bits().as_usize_bytes_rounded_up() - 1];
@ -319,11 +319,11 @@ fn test_signature_rsa_primitive_verification() {
fn rsa_test_keypair_coverage() {
const PRIVATE_KEY: &[u8] = include_bytes!("rsa_test_private_key_2048.p8");
let key_pair = signature::RsaKeyPair::from_pkcs8(PRIVATE_KEY).unwrap();
let key_pair = rsa::KeyPair::from_pkcs8(PRIVATE_KEY).unwrap();
// Test that `signature::KeyPair::PublicKey` is `rsa::public::Key`; if it
// Test that `signature::KeyPair::PublicKey` is `rsa::PublicKey`; if it
// were a separate type then it would need to be tested separately.
let _: &rsa::public::Key = key_pair.public_key();
let _: &rsa::PublicKey = key_pair.public_key();
test_public_key_coverage(key_pair.public());
// Test clones.
@ -336,7 +336,7 @@ fn rsa_test_keypair_coverage() {
);
}
fn test_public_key_coverage(key: &rsa::public::Key) {
fn test_public_key_coverage(key: &rsa::PublicKey) {
// Test `AsRef<[u8]>`
const PUBLIC_KEY: &[u8] = include_bytes!("rsa_test_public_key_2048.der");
assert_eq!(key.as_ref(), PUBLIC_KEY);