RSA: Replace RsaSubjectPublicKey::{modulus,exponent} with rsa::Public::{Modulus,Exponent}::be_bytes().

This is a step towards removing the heap-allocated and usually-unnecessary
`public_key: RsaSubjectPublicKey` field. The new API allows the caller to
better control how it stores/allocates the component values. This also removes
a couple of infallible `unwrap()`s.

This is a step towards removing `io::Positive` from the public API.

This is a breaking API change.
This commit is contained in:
Brian Smith 2021-09-24 10:29:50 -07:00
parent dd14e593e1
commit 511740c29f
8 changed files with 44 additions and 26 deletions

View File

@ -131,6 +131,7 @@ include = [
"tests/rsa_test_private_key_2048.p8",
"tests/rsa_test_public_key_2048.der",
"tests/rsa_test_public_key_2048_debug.txt",
"tests/rsa_test_public_modulus.bin",
"third_party/fiat/curve25519_32.h",
"third_party/fiat/curve25519_64.h",
"third_party/fiat/p256_32.h",

View File

@ -40,7 +40,7 @@ use crate::{
arithmetic::montgomery::*,
bits, bssl, c, error,
limb::{self, Limb, LimbMask, LIMB_BITS, LIMB_BYTES},
polyfill::u64_from_usize,
polyfill::{u64_from_usize, LeadingZerosStripped},
};
use alloc::{borrow::ToOwned as _, boxed::Box, vec, vec::Vec};
use core::{
@ -352,6 +352,12 @@ impl<M> Modulus<M> {
}
}
impl<M: PublicModulus> Modulus<M> {
pub fn be_bytes(&self) -> LeadingZerosStripped<impl ExactSizeIterator<Item = u8> + Clone + '_> {
LeadingZerosStripped::new(limb::unstripped_be_bytes(&self.limbs))
}
}
pub(crate) struct PartialModulus<'a, M> {
limbs: &'a [Limb],
n0: N0,

View File

@ -237,7 +237,7 @@ pub fn parse_big_endian_and_pad_consttime(
}
pub fn big_endian_from_limbs(limbs: &[Limb], out: &mut [u8]) {
let be_bytes = be_bytes(limbs);
let be_bytes = unstripped_be_bytes(limbs);
assert_eq!(out.len(), be_bytes.len());
out.iter_mut().zip(be_bytes).for_each(|(o, i)| {
*o = i;
@ -246,8 +246,9 @@ pub fn big_endian_from_limbs(limbs: &[Limb], out: &mut [u8]) {
/// Returns an iterator of the big-endian encoding of `limbs`.
///
/// The number of bytes returned will be a multiple of `LIMB_BYTES`.
fn be_bytes(limbs: &[Limb]) -> impl ExactSizeIterator<Item = u8> + Clone + '_ {
/// The number of bytes returned will be a multiple of `LIMB_BYTES`
/// and thus may be padded with leading zeros.
pub fn unstripped_be_bytes(limbs: &[Limb]) -> impl ExactSizeIterator<Item = u8> + Clone + '_ {
// The unwrap is safe because a slice can never be larger than `usize` bytes.
ArrayFlatMap::new(limbs.iter().rev().copied(), |limb| {
core::array::IntoIter::new(Limb::to_be_bytes(limb))

View File

@ -1,4 +1,5 @@
use crate::error;
use crate::polyfill::{ArrayFlatMap, LeadingZerosStripped};
use core::num::NonZeroU64;
/// The exponent `e` of an RSA public key.
@ -77,6 +78,18 @@ impl Exponent {
Ok(Self(value))
}
/// The big-endian encoding of the exponent.
///
/// There are no leading zeros.
pub fn be_bytes(&self) -> impl ExactSizeIterator<Item = u8> + 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()), |value| {
core::array::IntoIter::new(u64::to_be_bytes(value))
})
.unwrap();
LeadingZerosStripped::new(bytes)
}
}
impl From<Exponent> for NonZeroU64 {

View File

@ -48,6 +48,14 @@ impl Modulus {
Ok(Self { value, bits })
}
/// The big-endian encoding of the modulus.
///
/// There are no leading zeros.
#[inline]
pub fn be_bytes(&self) -> impl ExactSizeIterator<Item = u8> + Clone + '_ {
self.value.be_bytes()
}
/// The length of the modulus in bits.
#[inline]
pub fn len_bits(&self) -> bits::BitLength {

View File

@ -484,22 +484,6 @@ impl RsaSubjectPublicKey {
});
Ok(Self(bytes))
}
/// The public modulus (n).
pub fn modulus(&self) -> io::Positive {
// Parsing won't fail because we serialized it ourselves.
let (public_key, _exponent) =
super::parse_public_key(untrusted::Input::from(self.as_ref())).unwrap();
public_key
}
/// The public exponent (e).
pub fn exponent(&self) -> io::Positive {
// Parsing won't fail because we serialized it ourselves.
let (_public_key, exponent) =
super::parse_public_key(untrusted::Input::from(self.as_ref())).unwrap();
exponent
}
}
struct PrivatePrime<M: Prime> {

Binary file not shown.

View File

@ -329,13 +329,18 @@ fn rsa_test_public_key_coverage() {
// Test `Clone`.
let _ = key_pair.public_key().clone();
// Test `exponent()`.
// Test modulus encoding.
const PUBLIC_KEY_MODULUS_BE_BYTES: &[u8] = include_bytes!("rsa_test_public_modulus.bin");
assert_eq!(
&[0x01, 0x00, 0x01],
key_pair
.public_key()
.exponent()
.big_endian_without_leading_zero()
PUBLIC_KEY_MODULUS_BE_BYTES,
key_pair.public().n().be_bytes().collect::<Vec<_>>()
);
// Test exponent encoding.
const _65537: &[u8] = &[0x01, 0x00, 0x01];
assert_eq!(
_65537,
&key_pair.public().e().be_bytes().collect::<Vec<_>>()
);
// Test `Debug`