pkcs1v15: use BigUint
as Signature
's inner type (#298)
This one half of #220. Doing anything with a signature involves converting it from bytes into a `BigUint`, so this changes the inner type the latter which is more useful. It should also help address #272, since it will enable doing those sort of checks more eagerly.
This commit is contained in:
parent
a6fd36d5c5
commit
2ec8708541
117
src/pkcs1v15.rs
117
src/pkcs1v15.rs
@ -6,11 +6,11 @@
|
||||
//!
|
||||
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{boxed::Box, string::ToString, vec::Vec};
|
||||
use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
|
||||
use core::marker::PhantomData;
|
||||
use digest::Digest;
|
||||
use num_bigint::BigUint;
|
||||
use pkcs8::{
|
||||
spki::{
|
||||
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
|
||||
@ -125,7 +125,12 @@ impl SignatureScheme for Pkcs1v15Sign {
|
||||
}
|
||||
}
|
||||
|
||||
verify(pub_key, self.prefix.as_ref(), hashed, sig)
|
||||
verify(
|
||||
pub_key,
|
||||
self.prefix.as_ref(),
|
||||
hashed,
|
||||
&BigUint::from_bytes_be(sig),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,62 +139,46 @@ impl SignatureScheme for Pkcs1v15Sign {
|
||||
/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Signature {
|
||||
bytes: Box<[u8]>,
|
||||
inner: BigUint,
|
||||
}
|
||||
|
||||
impl SignatureEncoding for Signature {
|
||||
type Repr = Box<[u8]>;
|
||||
}
|
||||
|
||||
impl From<Box<[u8]>> for Signature {
|
||||
fn from(bytes: Box<[u8]>) -> Self {
|
||||
Self { bytes }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Signature {
|
||||
type Error = signature::Error;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> signature::Result<Self> {
|
||||
Ok(Self {
|
||||
bytes: bytes.into(),
|
||||
inner: BigUint::from_bytes_be(bytes),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Signature> for Box<[u8]> {
|
||||
fn from(signature: Signature) -> Box<[u8]> {
|
||||
signature.bytes
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Signature {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.bytes.as_ref()
|
||||
signature.inner.to_bytes_be().into_boxed_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Signature {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
|
||||
fmt.debug_list().entries(self.bytes.iter()).finish()
|
||||
fmt.debug_tuple("Signature")
|
||||
.field(&self.to_string())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl LowerHex for Signature {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
for byte in self.bytes.iter() {
|
||||
write!(f, "{:02x}", byte)?;
|
||||
}
|
||||
Ok(())
|
||||
write!(f, "{:x}", &self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl UpperHex for Signature {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
for byte in self.bytes.iter() {
|
||||
write!(f, "{:02X}", byte)?;
|
||||
}
|
||||
Ok(())
|
||||
write!(f, "{:X}", &self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,7 +283,7 @@ pub(crate) fn verify<PK: PublicKey>(
|
||||
pub_key: &PK,
|
||||
prefix: &[u8],
|
||||
hashed: &[u8],
|
||||
sig: &[u8],
|
||||
sig: &BigUint,
|
||||
) -> Result<()> {
|
||||
let hash_len = hashed.len();
|
||||
let t_len = prefix.len() + hashed.len();
|
||||
@ -303,7 +292,7 @@ pub(crate) fn verify<PK: PublicKey>(
|
||||
return Err(Error::Verification);
|
||||
}
|
||||
|
||||
let em = pub_key.raw_encryption_primitive(sig, pub_key.size())?;
|
||||
let em = pub_key.raw_int_encryption_primitive(sig, pub_key.size())?;
|
||||
|
||||
// EM = 0x00 || 0x01 || PS || 0x00 || T
|
||||
let mut ok = em[0].ct_eq(&0u8);
|
||||
@ -554,9 +543,9 @@ where
|
||||
D: Digest,
|
||||
{
|
||||
fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
|
||||
sign::<DummyRng, _>(None, &self.inner, &self.prefix, &D::digest(msg))
|
||||
.map(|v| v.into_boxed_slice().into())
|
||||
.map_err(|e| e.into())
|
||||
sign::<DummyRng, _>(None, &self.inner, &self.prefix, &D::digest(msg))?
|
||||
.as_slice()
|
||||
.try_into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,9 +558,9 @@ where
|
||||
rng: &mut impl CryptoRngCore,
|
||||
msg: &[u8],
|
||||
) -> signature::Result<Signature> {
|
||||
sign(Some(rng), &self.inner, &self.prefix, &D::digest(msg))
|
||||
.map(|v| v.into_boxed_slice().into())
|
||||
.map_err(|e| e.into())
|
||||
sign(Some(rng), &self.inner, &self.prefix, &D::digest(msg))?
|
||||
.as_slice()
|
||||
.try_into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -580,9 +569,9 @@ where
|
||||
D: Digest,
|
||||
{
|
||||
fn try_sign_digest(&self, digest: D) -> signature::Result<Signature> {
|
||||
sign::<DummyRng, _>(None, &self.inner, &self.prefix, &digest.finalize())
|
||||
.map(|v| v.into_boxed_slice().into())
|
||||
.map_err(|e| e.into())
|
||||
sign::<DummyRng, _>(None, &self.inner, &self.prefix, &digest.finalize())?
|
||||
.as_slice()
|
||||
.try_into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,9 +584,9 @@ where
|
||||
rng: &mut impl CryptoRngCore,
|
||||
digest: D,
|
||||
) -> signature::Result<Signature> {
|
||||
sign(Some(rng), &self.inner, &self.prefix, &digest.finalize())
|
||||
.map(|v| v.into_boxed_slice().into())
|
||||
.map_err(|e| e.into())
|
||||
sign(Some(rng), &self.inner, &self.prefix, &digest.finalize())?
|
||||
.as_slice()
|
||||
.try_into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -606,9 +595,9 @@ where
|
||||
D: Digest,
|
||||
{
|
||||
fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
|
||||
sign::<DummyRng, _>(None, &self.inner, &self.prefix, prehash)
|
||||
.map(|v| v.into_boxed_slice().into())
|
||||
.map_err(|e| e.into())
|
||||
sign::<DummyRng, _>(None, &self.inner, &self.prefix, prehash)?
|
||||
.as_slice()
|
||||
.try_into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,7 +738,7 @@ where
|
||||
&self.inner,
|
||||
&self.prefix.clone(),
|
||||
&D::digest(msg),
|
||||
signature.as_ref(),
|
||||
&signature.inner,
|
||||
)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
@ -764,7 +753,7 @@ where
|
||||
&self.inner,
|
||||
&self.prefix,
|
||||
&digest.finalize(),
|
||||
signature.as_ref(),
|
||||
&signature.inner,
|
||||
)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
@ -775,7 +764,7 @@ where
|
||||
D: Digest,
|
||||
{
|
||||
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> {
|
||||
verify(&self.inner, &self.prefix, prehash, signature.as_ref()).map_err(|e| e.into())
|
||||
verify(&self.inner, &self.prefix, prehash, &signature.inner).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1096,13 +1085,15 @@ mod tests {
|
||||
let signing_key = SigningKey::<Sha1>::new(priv_key);
|
||||
|
||||
for (text, expected) in &tests {
|
||||
let out = signing_key.sign(text.as_bytes());
|
||||
let out = signing_key.sign(text.as_bytes()).to_bytes();
|
||||
assert_ne!(out.as_ref(), text.as_bytes());
|
||||
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
|
||||
assert_eq!(out.as_ref(), expected);
|
||||
|
||||
let mut rng = ChaCha8Rng::from_seed([42; 32]);
|
||||
let out2 = signing_key.sign_with_rng(&mut rng, text.as_bytes());
|
||||
let out2 = signing_key
|
||||
.sign_with_rng(&mut rng, text.as_bytes())
|
||||
.to_bytes();
|
||||
assert_eq!(out2.as_ref(), expected);
|
||||
}
|
||||
}
|
||||
@ -1122,12 +1113,14 @@ mod tests {
|
||||
let signing_key = SigningKey::<Sha256>::new(priv_key);
|
||||
|
||||
for (text, expected) in &tests {
|
||||
let out = signing_key.sign(text.as_bytes());
|
||||
let out = signing_key.sign(text.as_bytes()).to_bytes();
|
||||
assert_ne!(out.as_ref(), text.as_bytes());
|
||||
assert_eq!(out.as_ref(), expected);
|
||||
|
||||
let mut rng = ChaCha8Rng::from_seed([42; 32]);
|
||||
let out2 = signing_key.sign_with_rng(&mut rng, text.as_bytes());
|
||||
let out2 = signing_key
|
||||
.sign_with_rng(&mut rng, text.as_bytes())
|
||||
.to_bytes();
|
||||
assert_eq!(out2.as_ref(), expected);
|
||||
}
|
||||
}
|
||||
@ -1147,12 +1140,14 @@ mod tests {
|
||||
let signing_key = SigningKey::<Sha3_256>::new(priv_key);
|
||||
|
||||
for (text, expected) in &tests {
|
||||
let out = signing_key.sign(text.as_bytes());
|
||||
let out = signing_key.sign(text.as_bytes()).to_bytes();
|
||||
assert_ne!(out.as_ref(), text.as_bytes());
|
||||
assert_eq!(out.as_ref(), expected);
|
||||
|
||||
let mut rng = ChaCha8Rng::from_seed([42; 32]);
|
||||
let out2 = signing_key.sign_with_rng(&mut rng, text.as_bytes());
|
||||
let out2 = signing_key
|
||||
.sign_with_rng(&mut rng, text.as_bytes())
|
||||
.to_bytes();
|
||||
assert_eq!(out2.as_ref(), expected);
|
||||
}
|
||||
}
|
||||
@ -1174,7 +1169,7 @@ mod tests {
|
||||
for (text, expected) in &tests {
|
||||
let mut digest = Sha1::new();
|
||||
digest.update(text.as_bytes());
|
||||
let out = signing_key.sign_digest(digest);
|
||||
let out = signing_key.sign_digest(digest).to_bytes();
|
||||
assert_ne!(out.as_ref(), text.as_bytes());
|
||||
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
|
||||
assert_eq!(out.as_ref(), expected);
|
||||
@ -1182,7 +1177,9 @@ mod tests {
|
||||
let mut rng = ChaCha8Rng::from_seed([42; 32]);
|
||||
let mut digest = Sha1::new();
|
||||
digest.update(text.as_bytes());
|
||||
let out2 = signing_key.sign_digest_with_rng(&mut rng, digest);
|
||||
let out2 = signing_key
|
||||
.sign_digest_with_rng(&mut rng, digest)
|
||||
.to_bytes();
|
||||
assert_eq!(out2.as_ref(), expected);
|
||||
}
|
||||
}
|
||||
@ -1324,15 +1321,15 @@ mod tests {
|
||||
let priv_key = get_private_key();
|
||||
|
||||
let signing_key = SigningKey::<Sha1>::new_unprefixed(priv_key);
|
||||
let sig = signing_key.sign_prehash(msg).expect("Failure during sign");
|
||||
let sig = signing_key
|
||||
.sign_prehash(msg)
|
||||
.expect("Failure during sign")
|
||||
.to_bytes();
|
||||
assert_eq!(sig.as_ref(), expected_sig);
|
||||
|
||||
let verifying_key = signing_key.verifying_key();
|
||||
verifying_key
|
||||
.verify_prehash(
|
||||
msg,
|
||||
&Signature::try_from(expected_sig.into_boxed_slice()).unwrap(),
|
||||
)
|
||||
.verify_prehash(msg, &Signature::try_from(expected_sig.as_slice()).unwrap())
|
||||
.expect("failed to verify");
|
||||
}
|
||||
}
|
||||
|
58
src/raw.rs
58
src/raw.rs
@ -1,7 +1,7 @@
|
||||
use alloc::vec::Vec;
|
||||
use num_bigint::BigUint;
|
||||
use rand_core::CryptoRngCore;
|
||||
use zeroize::Zeroize;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use crate::errors::Result;
|
||||
use crate::internals;
|
||||
@ -9,7 +9,13 @@ use crate::key::{RsaPrivateKey, RsaPublicKey};
|
||||
|
||||
pub trait EncryptionPrimitive {
|
||||
/// Do NOT use directly! Only for implementors.
|
||||
fn raw_encryption_primitive(&self, plaintext: &[u8], pad_size: usize) -> Result<Vec<u8>>;
|
||||
fn raw_encryption_primitive(&self, plaintext: &[u8], pad_size: usize) -> Result<Vec<u8>> {
|
||||
let int = Zeroizing::new(BigUint::from_bytes_be(plaintext));
|
||||
self.raw_int_encryption_primitive(&int, pad_size)
|
||||
}
|
||||
|
||||
fn raw_int_encryption_primitive(&self, plaintext: &BigUint, pad_size: usize)
|
||||
-> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
pub trait DecryptionPrimitive {
|
||||
@ -19,42 +25,40 @@ pub trait DecryptionPrimitive {
|
||||
rng: Option<&mut R>,
|
||||
ciphertext: &[u8],
|
||||
pad_size: usize,
|
||||
) -> Result<Vec<u8>> {
|
||||
let int = Zeroizing::new(BigUint::from_bytes_be(ciphertext));
|
||||
self.raw_int_decryption_primitive(rng, &int, pad_size)
|
||||
}
|
||||
|
||||
fn raw_int_decryption_primitive<R: CryptoRngCore + ?Sized>(
|
||||
&self,
|
||||
rng: Option<&mut R>,
|
||||
ciphertext: &BigUint,
|
||||
pad_size: usize,
|
||||
) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
impl EncryptionPrimitive for RsaPublicKey {
|
||||
fn raw_encryption_primitive(&self, plaintext: &[u8], pad_size: usize) -> Result<Vec<u8>> {
|
||||
let mut m = BigUint::from_bytes_be(plaintext);
|
||||
let mut c = internals::encrypt(self, &m);
|
||||
let mut c_bytes = c.to_bytes_be();
|
||||
let ciphertext = internals::left_pad(&c_bytes, pad_size);
|
||||
|
||||
// clear out tmp values
|
||||
m.zeroize();
|
||||
c.zeroize();
|
||||
c_bytes.zeroize();
|
||||
|
||||
ciphertext
|
||||
fn raw_int_encryption_primitive(
|
||||
&self,
|
||||
plaintext: &BigUint,
|
||||
pad_size: usize,
|
||||
) -> Result<Vec<u8>> {
|
||||
let c = Zeroizing::new(internals::encrypt(self, &plaintext));
|
||||
let c_bytes = Zeroizing::new(c.to_bytes_be());
|
||||
internals::left_pad(&c_bytes, pad_size)
|
||||
}
|
||||
}
|
||||
|
||||
impl DecryptionPrimitive for RsaPrivateKey {
|
||||
fn raw_decryption_primitive<R: CryptoRngCore + ?Sized>(
|
||||
fn raw_int_decryption_primitive<R: CryptoRngCore + ?Sized>(
|
||||
&self,
|
||||
rng: Option<&mut R>,
|
||||
ciphertext: &[u8],
|
||||
ciphertext: &BigUint,
|
||||
pad_size: usize,
|
||||
) -> Result<Vec<u8>> {
|
||||
let mut c = BigUint::from_bytes_be(ciphertext);
|
||||
let mut m = internals::decrypt_and_check(rng, self, &c)?;
|
||||
let mut m_bytes = m.to_bytes_be();
|
||||
let plaintext = internals::left_pad(&m_bytes, pad_size);
|
||||
|
||||
// clear tmp values
|
||||
c.zeroize();
|
||||
m.zeroize();
|
||||
m_bytes.zeroize();
|
||||
|
||||
plaintext
|
||||
let m = Zeroizing::new(internals::decrypt_and_check(rng, self, &ciphertext)?);
|
||||
let m_bytes = Zeroizing::new(m.to_bytes_be());
|
||||
internals::left_pad(&m_bytes, pad_size)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user