chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

10
vendor/rsa/src/algorithms.rs vendored Normal file
View File

@@ -0,0 +1,10 @@
//! Useful algorithms related to RSA.
mod mgf;
pub(crate) mod generate;
pub(crate) mod oaep;
pub(crate) mod pad;
pub(crate) mod pkcs1v15;
pub(crate) mod pss;
pub(crate) mod rsa;

166
vendor/rsa/src/algorithms/generate.rs vendored Normal file
View File

@@ -0,0 +1,166 @@
//! Generate prime components for the RSA Private Key
use alloc::vec::Vec;
use num_bigint::{BigUint, RandPrime};
#[allow(unused_imports)]
use num_traits::Float;
use num_traits::Zero;
use rand_core::CryptoRngCore;
use crate::{
algorithms::rsa::{compute_modulus, compute_private_exponent_euler_totient},
errors::{Error, Result},
};
pub struct RsaPrivateKeyComponents {
pub n: BigUint,
pub e: BigUint,
pub d: BigUint,
pub primes: Vec<BigUint>,
}
/// Generates a multi-prime RSA keypair of the given bit size, public exponent,
/// and the given random source, as suggested in [1]. Although the public
/// keys are compatible (actually, indistinguishable) from the 2-prime case,
/// the private keys are not. Thus it may not be possible to export multi-prime
/// private keys in certain formats or to subsequently import them into other
/// code.
///
/// Table 1 in [2] suggests maximum numbers of primes for a given size.
///
/// [1]: https://patents.google.com/patent/US4405829A/en
/// [2]: http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
pub(crate) fn generate_multi_prime_key_with_exp<R: CryptoRngCore + ?Sized>(
rng: &mut R,
nprimes: usize,
bit_size: usize,
exp: &BigUint,
) -> Result<RsaPrivateKeyComponents> {
if nprimes < 2 {
return Err(Error::NprimesTooSmall);
}
if bit_size < 64 {
let prime_limit = (1u64 << (bit_size / nprimes) as u64) as f64;
// pi aproximates the number of primes less than prime_limit
let mut pi = prime_limit / (prime_limit.ln() - 1f64);
// Generated primes start with 0b11, so we can only use a quarter of them.
pi /= 4f64;
// Use a factor of two to ensure that key generation terminates in a
// reasonable amount of time.
pi /= 2f64;
if pi < nprimes as f64 {
return Err(Error::TooFewPrimes);
}
}
let mut primes = vec![BigUint::zero(); nprimes];
let n_final: BigUint;
let d_final: BigUint;
'next: loop {
let mut todo = bit_size;
// `gen_prime` should set the top two bits in each prime.
// Thus each prime has the form
// p_i = 2^bitlen(p_i) × 0.11... (in base 2).
// And the product is:
// P = 2^todo × α
// where α is the product of nprimes numbers of the form 0.11...
//
// If α < 1/2 (which can happen for nprimes > 2), we need to
// shift todo to compensate for lost bits: the mean value of 0.11...
// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
// will give good results.
if nprimes >= 7 {
todo += (nprimes - 2) / 5;
}
for (i, prime) in primes.iter_mut().enumerate() {
*prime = rng.gen_prime(todo / (nprimes - i));
todo -= prime.bits();
}
// Makes sure that primes is pairwise unequal.
for (i, prime1) in primes.iter().enumerate() {
for prime2 in primes.iter().take(i) {
if prime1 == prime2 {
continue 'next;
}
}
}
let n = compute_modulus(&primes);
if n.bits() != bit_size {
// This should never happen for nprimes == 2 because
// gen_prime should set the top two bits in each prime.
// For nprimes > 2 we hope it does not happen often.
continue 'next;
}
if let Ok(d) = compute_private_exponent_euler_totient(&primes, exp) {
n_final = n;
d_final = d;
break;
}
}
Ok(RsaPrivateKeyComponents {
n: n_final,
e: exp.clone(),
d: d_final,
primes,
})
}
#[cfg(test)]
mod tests {
use super::*;
use num_bigint::BigUint;
use num_traits::FromPrimitive;
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
const EXP: u64 = 65537;
#[test]
fn test_impossible_keys() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
for i in 0..32 {
let _ = generate_multi_prime_key_with_exp(&mut rng, 2, i, &exp);
let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, &exp);
let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, &exp);
let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, &exp);
}
}
macro_rules! key_generation {
($name:ident, $multi:expr, $size:expr) => {
#[test]
fn $name() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
for _ in 0..10 {
let components =
generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap();
assert_eq!(components.n.bits(), $size);
assert_eq!(components.primes.len(), $multi);
}
}
};
}
key_generation!(key_generation_128, 2, 128);
key_generation!(key_generation_1024, 2, 1024);
key_generation!(key_generation_multi_3_256, 3, 256);
key_generation!(key_generation_multi_4_64, 4, 64);
key_generation!(key_generation_multi_5_64, 5, 64);
key_generation!(key_generation_multi_8_576, 8, 576);
key_generation!(key_generation_multi_16_1024, 16, 1024);
}

75
vendor/rsa/src/algorithms/mgf.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
//! Mask generation function common to both PSS and OAEP padding
use digest::{Digest, DynDigest, FixedOutputReset};
/// Mask generation function.
///
/// Panics if out is larger than 2**32. This is in accordance with RFC 8017 - PKCS #1 B.2.1
pub(crate) fn mgf1_xor(out: &mut [u8], digest: &mut dyn DynDigest, seed: &[u8]) {
let mut counter = [0u8; 4];
let mut i = 0;
const MAX_LEN: u64 = core::u32::MAX as u64 + 1;
assert!(out.len() as u64 <= MAX_LEN);
while i < out.len() {
let mut digest_input = vec![0u8; seed.len() + 4];
digest_input[0..seed.len()].copy_from_slice(seed);
digest_input[seed.len()..].copy_from_slice(&counter);
digest.update(digest_input.as_slice());
let digest_output = &*digest.finalize_reset();
let mut j = 0;
loop {
if j >= digest_output.len() || i >= out.len() {
break;
}
out[i] ^= digest_output[j];
j += 1;
i += 1;
}
inc_counter(&mut counter);
}
}
/// Mask generation function.
///
/// Panics if out is larger than 2**32. This is in accordance with RFC 8017 - PKCS #1 B.2.1
pub(crate) fn mgf1_xor_digest<D>(out: &mut [u8], digest: &mut D, seed: &[u8])
where
D: Digest + FixedOutputReset,
{
let mut counter = [0u8; 4];
let mut i = 0;
const MAX_LEN: u64 = core::u32::MAX as u64 + 1;
assert!(out.len() as u64 <= MAX_LEN);
while i < out.len() {
Digest::update(digest, seed);
Digest::update(digest, counter);
let digest_output = digest.finalize_reset();
let mut j = 0;
loop {
if j >= digest_output.len() || i >= out.len() {
break;
}
out[i] ^= digest_output[j];
j += 1;
i += 1;
}
inc_counter(&mut counter);
}
}
fn inc_counter(counter: &mut [u8; 4]) {
for i in (0..4).rev() {
counter[i] = counter[i].wrapping_add(1);
if counter[i] != 0 {
// No overflow
return;
}
}
}

246
vendor/rsa/src/algorithms/oaep.rs vendored Normal file
View File

@@ -0,0 +1,246 @@
//! Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
//!
use alloc::string::String;
use alloc::vec::Vec;
use digest::{Digest, DynDigest, FixedOutputReset};
use rand_core::CryptoRngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::Zeroizing;
use super::mgf::{mgf1_xor, mgf1_xor_digest};
use crate::errors::{Error, Result};
// 2**61 -1 (pow is not const yet)
// TODO: This is the maximum for SHA-1, unclear from the RFC what the values are for other hashing functions.
const MAX_LABEL_LEN: u64 = 2_305_843_009_213_693_951;
#[inline]
fn encrypt_internal<R: CryptoRngCore + ?Sized, MGF: FnMut(&mut [u8], &mut [u8])>(
rng: &mut R,
msg: &[u8],
p_hash: &[u8],
h_size: usize,
k: usize,
mut mgf: MGF,
) -> Result<Zeroizing<Vec<u8>>> {
if msg.len() + 2 * h_size + 2 > k {
return Err(Error::MessageTooLong);
}
let mut em = Zeroizing::new(vec![0u8; k]);
let (_, payload) = em.split_at_mut(1);
let (seed, db) = payload.split_at_mut(h_size);
rng.fill_bytes(seed);
// Data block DB = pHash || PS || 01 || M
let db_len = k - h_size - 1;
db[0..h_size].copy_from_slice(p_hash);
db[db_len - msg.len() - 1] = 1;
db[db_len - msg.len()..].copy_from_slice(msg);
mgf(seed, db);
Ok(em)
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
msg: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
k: usize,
) -> Result<Zeroizing<Vec<u8>>> {
let h_size = digest.output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::LabelTooLong);
}
digest.update(label.as_bytes());
let p_hash = digest.finalize_reset();
encrypt_internal(rng, msg, &p_hash, h_size, k, |seed, db| {
mgf1_xor(db, mgf_digest, seed);
mgf1_xor(seed, mgf_digest, db);
})
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_encrypt_digest<
R: CryptoRngCore + ?Sized,
D: Digest,
MGD: Digest + FixedOutputReset,
>(
rng: &mut R,
msg: &[u8],
label: Option<String>,
k: usize,
) -> Result<Zeroizing<Vec<u8>>> {
let h_size = <D as Digest>::output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::LabelTooLong);
}
let p_hash = D::digest(label.as_bytes());
encrypt_internal(rng, msg, &p_hash, h_size, k, |seed, db| {
let mut mgf_digest = MGD::new();
mgf1_xor_digest(db, &mut mgf_digest, seed);
mgf1_xor_digest(seed, &mut mgf_digest, db);
})
}
///Decrypts OAEP padding.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_decrypt(
em: &mut [u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
k: usize,
) -> Result<Vec<u8>> {
let h_size = digest.output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::Decryption);
}
digest.update(label.as_bytes());
let expected_p_hash = digest.finalize_reset();
let res = decrypt_inner(em, h_size, &expected_p_hash, k, |seed, db| {
mgf1_xor(seed, mgf_digest, db);
mgf1_xor(db, mgf_digest, seed);
})?;
if res.is_none().into() {
return Err(Error::Decryption);
}
let (out, index) = res.unwrap();
Ok(out[index as usize..].to_vec())
}
///Decrypts OAEP padding.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_decrypt_digest<D: Digest, MGD: Digest + FixedOutputReset>(
em: &mut [u8],
label: Option<String>,
k: usize,
) -> Result<Vec<u8>> {
let h_size = <D as Digest>::output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::LabelTooLong);
}
let expected_p_hash = D::digest(label.as_bytes());
let res = decrypt_inner(em, h_size, &expected_p_hash, k, |seed, db| {
let mut mgf_digest = MGD::new();
mgf1_xor_digest(seed, &mut mgf_digest, db);
mgf1_xor_digest(db, &mut mgf_digest, seed);
})?;
if res.is_none().into() {
return Err(Error::Decryption);
}
let (out, index) = res.unwrap();
Ok(out[index as usize..].to_vec())
}
/// Decrypts OAEP padding. It returns one or zero in valid that indicates whether the
/// plaintext was correctly structured.
#[inline]
fn decrypt_inner<MGF: FnMut(&mut [u8], &mut [u8])>(
em: &mut [u8],
h_size: usize,
expected_p_hash: &[u8],
k: usize,
mut mgf: MGF,
) -> Result<CtOption<(Vec<u8>, u32)>> {
if k < 11 {
return Err(Error::Decryption);
}
if k < h_size * 2 + 2 {
return Err(Error::Decryption);
}
let first_byte_is_zero = em[0].ct_eq(&0u8);
let (_, payload) = em.split_at_mut(1);
let (seed, db) = payload.split_at_mut(h_size);
mgf(seed, db);
let hash_are_equal = db[0..h_size].ct_eq(expected_p_hash);
// The remainder of the plaintext must be zero or more 0x00, followed
// by 0x01, followed by the message.
// looking_for_index: 1 if we are still looking for the 0x01
// index: the offset of the first 0x01 byte
// zero_before_one: 1 if we saw a non-zero byte before the 1
let mut looking_for_index = Choice::from(1u8);
let mut index = 0u32;
let mut nonzero_before_one = Choice::from(0u8);
for (i, el) in db.iter().skip(h_size).enumerate() {
let equals0 = el.ct_eq(&0u8);
let equals1 = el.ct_eq(&1u8);
index.conditional_assign(&(i as u32), looking_for_index & equals1);
looking_for_index &= !equals1;
nonzero_before_one |= looking_for_index & !equals0;
}
let valid = first_byte_is_zero & hash_are_equal & !nonzero_before_one & !looking_for_index;
Ok(CtOption::new(
(em.to_vec(), index + 2 + (h_size * 2) as u32),
valid,
))
}

55
vendor/rsa/src/algorithms/pad.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
//! Special handling for converting the BigUint to u8 vectors
use alloc::vec::Vec;
use num_bigint::BigUint;
use zeroize::Zeroizing;
use crate::errors::{Error, Result};
/// Returns a new vector of the given length, with 0s left padded.
#[inline]
fn left_pad(input: &[u8], padded_len: usize) -> Result<Vec<u8>> {
if input.len() > padded_len {
return Err(Error::InvalidPadLen);
}
let mut out = vec![0u8; padded_len];
out[padded_len - input.len()..].copy_from_slice(input);
Ok(out)
}
/// Converts input to the new vector of the given length, using BE and with 0s left padded.
#[inline]
pub(crate) fn uint_to_be_pad(input: BigUint, padded_len: usize) -> Result<Vec<u8>> {
left_pad(&input.to_bytes_be(), padded_len)
}
/// Converts input to the new vector of the given length, using BE and with 0s left padded.
#[inline]
pub(crate) fn uint_to_zeroizing_be_pad(input: BigUint, padded_len: usize) -> Result<Vec<u8>> {
let m = Zeroizing::new(input);
let m = Zeroizing::new(m.to_bytes_be());
left_pad(&m, padded_len)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_left_pad() {
const INPUT_LEN: usize = 3;
let input = vec![0u8; INPUT_LEN];
// input len < padded len
let padded = left_pad(&input, INPUT_LEN + 1).unwrap();
assert_eq!(padded.len(), INPUT_LEN + 1);
// input len == padded len
let padded = left_pad(&input, INPUT_LEN).unwrap();
assert_eq!(padded.len(), INPUT_LEN);
// input len > padded len
let padded = left_pad(&input, INPUT_LEN - 1);
assert!(padded.is_err());
}
}

207
vendor/rsa/src/algorithms/pkcs1v15.rs vendored Normal file
View File

@@ -0,0 +1,207 @@
//! PKCS#1 v1.5 support as described in [RFC8017 § 8.2].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pkcs1-v15-signatures).
//!
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
use alloc::vec::Vec;
use digest::Digest;
use pkcs8::AssociatedOid;
use rand_core::CryptoRngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroizing;
use crate::errors::{Error, Result};
/// Fills the provided slice with random values, which are guaranteed
/// to not be zero.
#[inline]
fn non_zero_random_bytes<R: CryptoRngCore + ?Sized>(rng: &mut R, data: &mut [u8]) {
rng.fill_bytes(data);
for el in data {
if *el == 0u8 {
// TODO: break after a certain amount of time
while *el == 0u8 {
rng.fill_bytes(core::slice::from_mut(el));
}
}
}
}
/// Applied the padding scheme from PKCS#1 v1.5 for encryption. The message must be no longer than
/// the length of the public modulus minus 11 bytes.
pub(crate) fn pkcs1v15_encrypt_pad<R>(
rng: &mut R,
msg: &[u8],
k: usize,
) -> Result<Zeroizing<Vec<u8>>>
where
R: CryptoRngCore + ?Sized,
{
if msg.len() + 11 > k {
return Err(Error::MessageTooLong);
}
// EM = 0x00 || 0x02 || PS || 0x00 || M
let mut em = Zeroizing::new(vec![0u8; k]);
em[1] = 2;
non_zero_random_bytes(rng, &mut em[2..k - msg.len() - 1]);
em[k - msg.len() - 1] = 0;
em[k - msg.len()..].copy_from_slice(msg);
Ok(em)
}
/// Removes the encryption padding scheme from PKCS#1 v1.5.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key. See
/// `decrypt_session_key` for a way of solving this problem.
#[inline]
pub(crate) fn pkcs1v15_encrypt_unpad(em: Vec<u8>, k: usize) -> Result<Vec<u8>> {
let (valid, out, index) = decrypt_inner(em, k)?;
if valid == 0 {
return Err(Error::Decryption);
}
Ok(out[index as usize..].to_vec())
}
/// Removes the PKCS1v15 padding It returns one or zero in valid that indicates whether the
/// plaintext was correctly structured. In either case, the plaintext is
/// returned in em so that it may be read independently of whether it was valid
/// in order to maintain constant memory access patterns. If the plaintext was
/// valid then index contains the index of the original message in em.
#[inline]
fn decrypt_inner(em: Vec<u8>, k: usize) -> Result<(u8, Vec<u8>, u32)> {
if k < 11 {
return Err(Error::Decryption);
}
let first_byte_is_zero = em[0].ct_eq(&0u8);
let second_byte_is_two = em[1].ct_eq(&2u8);
// The remainder of the plaintext must be a string of non-zero random
// octets, followed by a 0, followed by the message.
// looking_for_index: 1 iff we are still looking for the zero.
// index: the offset of the first zero byte.
let mut looking_for_index = 1u8;
let mut index = 0u32;
for (i, el) in em.iter().enumerate().skip(2) {
let equals0 = el.ct_eq(&0u8);
index.conditional_assign(&(i as u32), Choice::from(looking_for_index) & equals0);
looking_for_index.conditional_assign(&0u8, equals0);
}
// The PS padding must be at least 8 bytes long, and it starts two
// bytes into em.
// TODO: WARNING: THIS MUST BE CONSTANT TIME CHECK:
// Ref: https://github.com/dalek-cryptography/subtle/issues/20
// This is currently copy & paste from the constant time impl in
// go, but very likely not sufficient.
let valid_ps = Choice::from((((2i32 + 8i32 - index as i32 - 1i32) >> 31) & 1) as u8);
let valid =
first_byte_is_zero & second_byte_is_two & Choice::from(!looking_for_index & 1) & valid_ps;
index = u32::conditional_select(&0, &(index + 1), valid);
Ok((valid.unwrap_u8(), em, index))
}
#[inline]
pub(crate) fn pkcs1v15_sign_pad(prefix: &[u8], hashed: &[u8], k: usize) -> Result<Vec<u8>> {
let hash_len = hashed.len();
let t_len = prefix.len() + hashed.len();
if k < t_len + 11 {
return Err(Error::MessageTooLong);
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
let mut em = vec![0xff; k];
em[0] = 0;
em[1] = 1;
em[k - t_len - 1] = 0;
em[k - t_len..k - hash_len].copy_from_slice(prefix);
em[k - hash_len..k].copy_from_slice(hashed);
Ok(em)
}
#[inline]
pub(crate) fn pkcs1v15_sign_unpad(prefix: &[u8], hashed: &[u8], em: &[u8], k: usize) -> Result<()> {
let hash_len = hashed.len();
let t_len = prefix.len() + hashed.len();
if k < t_len + 11 {
return Err(Error::Verification);
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
let mut ok = em[0].ct_eq(&0u8);
ok &= em[1].ct_eq(&1u8);
ok &= em[k - hash_len..k].ct_eq(hashed);
ok &= em[k - t_len..k - hash_len].ct_eq(prefix);
ok &= em[k - t_len - 1].ct_eq(&0u8);
for el in em.iter().skip(2).take(k - t_len - 3) {
ok &= el.ct_eq(&0xff)
}
if ok.unwrap_u8() != 1 {
return Err(Error::Verification);
}
Ok(())
}
/// prefix = 0x30 <oid_len + 8 + digest_len> 0x30 <oid_len + 4> 0x06 <oid_len> oid 0x05 0x00 0x04 <digest_len>
#[inline]
pub(crate) fn pkcs1v15_generate_prefix<D>() -> Vec<u8>
where
D: Digest + AssociatedOid,
{
let oid = D::OID.as_bytes();
let oid_len = oid.len() as u8;
let digest_len = <D as Digest>::output_size() as u8;
let mut v = vec![
0x30,
oid_len + 8 + digest_len,
0x30,
oid_len + 4,
0x6,
oid_len,
];
v.extend_from_slice(oid);
v.extend_from_slice(&[0x05, 0x00, 0x04, digest_len]);
v
}
#[cfg(test)]
mod tests {
use super::*;
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
#[test]
fn test_non_zero_bytes() {
for _ in 0..10 {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let mut b = vec![0u8; 512];
non_zero_random_bytes(&mut rng, &mut b);
for el in &b {
assert_ne!(*el, 0u8);
}
}
}
#[test]
fn test_encrypt_tiny_no_crash() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = 8;
let message = vec![1u8; 4];
let res = pkcs1v15_encrypt_pad(&mut rng, &message, k);
assert_eq!(res, Err(Error::MessageTooLong));
}
}

334
vendor/rsa/src/algorithms/pss.rs vendored Normal file
View File

@@ -0,0 +1,334 @@
//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
//!
//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pss-signatures).
//!
//! [Probabilistic Signature Scheme]: https://en.wikipedia.org/wiki/Probabilistic_signature_scheme
//! [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
use alloc::vec::Vec;
use digest::{Digest, DynDigest, FixedOutputReset};
use subtle::{Choice, ConstantTimeEq};
use super::mgf::{mgf1_xor, mgf1_xor_digest};
use crate::errors::{Error, Result};
pub(crate) fn emsa_pss_encode(
m_hash: &[u8],
em_bits: usize,
salt: &[u8],
hash: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
// See [1], section 9.1.1
let h_len = hash.output_size();
let s_len = salt.len();
let em_len = (em_bits + 7) / 8;
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.
//
// 2. Let mHash = Hash(M), an octet string of length hLen.
if m_hash.len() != h_len {
return Err(Error::InputNotHashed);
}
// 3. If em_len < h_len + s_len + 2, output "encoding error" and stop.
if em_len < h_len + s_len + 2 {
// TODO: Key size too small
return Err(Error::Internal);
}
let mut em = vec![0; em_len];
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - db.len()];
// 4. Generate a random octet string salt of length s_len; if s_len = 0,
// then salt is the empty string.
//
// 5. Let
// M' = (0x)00 00 00 00 00 00 00 00 || m_hash || salt;
//
// M' is an octet string of length 8 + h_len + s_len with eight
// initial zero octets.
//
// 6. Let H = Hash(M'), an octet string of length h_len.
let prefix = [0u8; 8];
hash.update(&prefix);
hash.update(m_hash);
hash.update(salt);
let hashed = hash.finalize_reset();
h.copy_from_slice(&hashed);
// 7. Generate an octet string PS consisting of em_len - s_len - h_len - 2
// zero octets. The length of PS may be 0.
//
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);
// 9. Let dbMask = MGF(H, emLen - hLen - 1).
//
// 10. Let maskedDB = DB \xor dbMask.
mgf1_xor(db, hash, h);
// 11. Set the leftmost 8 * em_len - em_bits bits of the leftmost octet in
// maskedDB to zero.
db[0] &= 0xFF >> (8 * em_len - em_bits);
// 12. Let EM = maskedDB || H || 0xbc.
em[em_len - 1] = 0xBC;
Ok(em)
}
pub(crate) fn emsa_pss_encode_digest<D>(
m_hash: &[u8],
em_bits: usize,
salt: &[u8],
) -> Result<Vec<u8>>
where
D: Digest + FixedOutputReset,
{
// See [1], section 9.1.1
let h_len = <D as Digest>::output_size();
let s_len = salt.len();
let em_len = (em_bits + 7) / 8;
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.
//
// 2. Let mHash = Hash(M), an octet string of length hLen.
if m_hash.len() != h_len {
return Err(Error::InputNotHashed);
}
// 3. If em_len < h_len + s_len + 2, output "encoding error" and stop.
if em_len < h_len + s_len + 2 {
// TODO: Key size too small
return Err(Error::Internal);
}
let mut em = vec![0; em_len];
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - db.len()];
// 4. Generate a random octet string salt of length s_len; if s_len = 0,
// then salt is the empty string.
//
// 5. Let
// M' = (0x)00 00 00 00 00 00 00 00 || m_hash || salt;
//
// M' is an octet string of length 8 + h_len + s_len with eight
// initial zero octets.
//
// 6. Let H = Hash(M'), an octet string of length h_len.
let prefix = [0u8; 8];
let mut hash = D::new();
Digest::update(&mut hash, prefix);
Digest::update(&mut hash, m_hash);
Digest::update(&mut hash, salt);
let hashed = hash.finalize_reset();
h.copy_from_slice(&hashed);
// 7. Generate an octet string PS consisting of em_len - s_len - h_len - 2
// zero octets. The length of PS may be 0.
//
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);
// 9. Let dbMask = MGF(H, emLen - hLen - 1).
//
// 10. Let maskedDB = DB \xor dbMask.
mgf1_xor_digest(db, &mut hash, h);
// 11. Set the leftmost 8 * em_len - em_bits bits of the leftmost octet in
// maskedDB to zero.
db[0] &= 0xFF >> (8 * em_len - em_bits);
// 12. Let EM = maskedDB || H || 0xbc.
em[em_len - 1] = 0xBC;
Ok(em)
}
fn emsa_pss_verify_pre<'a>(
m_hash: &[u8],
em: &'a mut [u8],
em_bits: usize,
s_len: usize,
h_len: usize,
) -> Result<(&'a mut [u8], &'a mut [u8])> {
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.
//
// 2. Let mHash = Hash(M), an octet string of length hLen
if m_hash.len() != h_len {
return Err(Error::Verification);
}
// 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
let em_len = em.len(); //(em_bits + 7) / 8;
if em_len < h_len + s_len + 2 {
return Err(Error::Verification);
}
// 4. If the rightmost octet of EM does not have hexadecimal value
// 0xbc, output "inconsistent" and stop.
if em[em.len() - 1] != 0xBC {
return Err(Error::Verification);
}
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..h_len];
// 6. If the leftmost 8 * em_len - em_bits bits of the leftmost octet in
// maskedDB are not all equal to zero, output "inconsistent" and
// stop.
if db[0]
& (0xFF_u8
.checked_shl(8 - (8 * em_len - em_bits) as u32)
.unwrap_or(0))
!= 0
{
return Err(Error::Verification);
}
Ok((db, h))
}
fn emsa_pss_verify_salt(db: &[u8], em_len: usize, s_len: usize, h_len: usize) -> Choice {
// 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
// or if the octet at position emLen - hLen - sLen - 1 (the leftmost
// position is "position 1") does not have hexadecimal value 0x01,
// output "inconsistent" and stop.
let (zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
let valid: Choice = zeroes
.iter()
.fold(Choice::from(1u8), |a, e| a & e.ct_eq(&0x00));
valid & rest[0].ct_eq(&0x01)
}
pub(crate) fn emsa_pss_verify(
m_hash: &[u8],
em: &mut [u8],
s_len: usize,
hash: &mut dyn DynDigest,
key_bits: usize,
) -> Result<()> {
let em_bits = key_bits - 1;
let em_len = (em_bits + 7) / 8;
let key_len = (key_bits + 7) / 8;
let h_len = hash.output_size();
let em = &mut em[key_len - em_len..];
let (db, h) = emsa_pss_verify_pre(m_hash, em, em_bits, s_len, h_len)?;
// 7. Let dbMask = MGF(H, em_len - h_len - 1)
//
// 8. Let DB = maskedDB \xor dbMask
mgf1_xor(db, hash, &*h);
// 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
// to zero.
db[0] &= 0xFF >> /*uint*/(8 * em_len - em_bits);
let salt_valid = emsa_pss_verify_salt(db, em_len, s_len, h_len);
// 11. Let salt be the last s_len octets of DB.
let salt = &db[db.len() - s_len..];
// 12. Let
// M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
// M' is an octet string of length 8 + hLen + sLen with eight
// initial zero octets.
//
// 13. Let H' = Hash(M'), an octet string of length hLen.
let prefix = [0u8; 8];
hash.update(&prefix[..]);
hash.update(m_hash);
hash.update(salt);
let h0 = hash.finalize_reset();
// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if (salt_valid & h0.ct_eq(h)).into() {
Ok(())
} else {
Err(Error::Verification)
}
}
pub(crate) fn emsa_pss_verify_digest<D>(
m_hash: &[u8],
em: &mut [u8],
s_len: usize,
key_bits: usize,
) -> Result<()>
where
D: Digest + FixedOutputReset,
{
let em_bits = key_bits - 1;
let em_len = (em_bits + 7) / 8;
let key_len = (key_bits + 7) / 8;
let h_len = <D as Digest>::output_size();
let em = &mut em[key_len - em_len..];
let (db, h) = emsa_pss_verify_pre(m_hash, em, em_bits, s_len, h_len)?;
let mut hash = D::new();
// 7. Let dbMask = MGF(H, em_len - h_len - 1)
//
// 8. Let DB = maskedDB \xor dbMask
mgf1_xor_digest::<D>(db, &mut hash, &*h);
// 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
// to zero.
db[0] &= 0xFF >> /*uint*/(8 * em_len - em_bits);
let salt_valid = emsa_pss_verify_salt(db, em_len, s_len, h_len);
// 11. Let salt be the last s_len octets of DB.
let salt = &db[db.len() - s_len..];
// 12. Let
// M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
// M' is an octet string of length 8 + hLen + sLen with eight
// initial zero octets.
//
// 13. Let H' = Hash(M'), an octet string of length hLen.
let prefix = [0u8; 8];
Digest::update(&mut hash, &prefix[..]);
Digest::update(&mut hash, m_hash);
Digest::update(&mut hash, salt);
let h0 = hash.finalize_reset();
// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if (salt_valid & h0.ct_eq(h)).into() {
Ok(())
} else {
Err(Error::Verification)
}
}

328
vendor/rsa/src/algorithms/rsa.rs vendored Normal file
View File

@@ -0,0 +1,328 @@
//! Generic RSA implementation
use alloc::borrow::Cow;
use alloc::vec::Vec;
use num_bigint::{BigInt, BigUint, IntoBigInt, IntoBigUint, ModInverse, RandBigInt, ToBigInt};
use num_integer::{sqrt, Integer};
use num_traits::{FromPrimitive, One, Pow, Signed, Zero};
use rand_core::CryptoRngCore;
use zeroize::{Zeroize, Zeroizing};
use crate::errors::{Error, Result};
use crate::traits::{PrivateKeyParts, PublicKeyParts};
/// ⚠️ Raw RSA encryption of m with the public key. No padding is performed.
///
/// # ☢️️ WARNING: HAZARDOUS API ☢️
///
/// Use this function with great care! Raw RSA should never be used without an appropriate padding
/// or signature scheme. See the [module-level documentation][crate::hazmat] for more information.
#[inline]
pub fn rsa_encrypt<K: PublicKeyParts>(key: &K, m: &BigUint) -> Result<BigUint> {
Ok(m.modpow(key.e(), key.n()))
}
/// ⚠️ Performs raw RSA decryption with no padding or error checking.
///
/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed.
///
/// # ☢️️ WARNING: HAZARDOUS API ☢️
///
/// Use this function with great care! Raw RSA should never be used without an appropriate padding
/// or signature scheme. See the [module-level documentation][crate::hazmat] for more information.
#[inline]
pub fn rsa_decrypt<R: CryptoRngCore + ?Sized>(
mut rng: Option<&mut R>,
priv_key: &impl PrivateKeyParts,
c: &BigUint,
) -> Result<BigUint> {
if c >= priv_key.n() {
return Err(Error::Decryption);
}
if priv_key.n().is_zero() {
return Err(Error::Decryption);
}
let mut ir = None;
let c = if let Some(ref mut rng) = rng {
let (blinded, unblinder) = blind(rng, priv_key, c);
ir = Some(unblinder);
Cow::Owned(blinded)
} else {
Cow::Borrowed(c)
};
let dp = priv_key.dp();
let dq = priv_key.dq();
let qinv = priv_key.qinv();
let crt_values = priv_key.crt_values();
let m = match (dp, dq, qinv, crt_values) {
(Some(dp), Some(dq), Some(qinv), Some(crt_values)) => {
// We have the precalculated values needed for the CRT.
let p = &priv_key.primes()[0];
let q = &priv_key.primes()[1];
let mut m = c.modpow(dp, p).into_bigint().unwrap();
let mut m2 = c.modpow(dq, q).into_bigint().unwrap();
m -= &m2;
let mut primes: Vec<_> = priv_key
.primes()
.iter()
.map(ToBigInt::to_bigint)
.map(Option::unwrap)
.collect();
while m.is_negative() {
m += &primes[0];
}
m *= qinv;
m %= &primes[0];
m *= &primes[1];
m += &m2;
let mut c = c.into_owned().into_bigint().unwrap();
for (i, value) in crt_values.iter().enumerate() {
let prime = &primes[2 + i];
m2 = c.modpow(&value.exp, prime);
m2 -= &m;
m2 *= &value.coeff;
m2 %= prime;
while m2.is_negative() {
m2 += prime;
}
m2 *= &value.r;
m += &m2;
}
// clear tmp values
for prime in primes.iter_mut() {
prime.zeroize();
}
primes.clear();
c.zeroize();
m2.zeroize();
m.into_biguint().expect("failed to decrypt")
}
_ => c.modpow(priv_key.d(), priv_key.n()),
};
match ir {
Some(ref ir) => {
// unblind
Ok(unblind(priv_key, &m, ir))
}
None => Ok(m),
}
}
/// ⚠️ Performs raw RSA decryption with no padding.
///
/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed. This will also
/// check for errors in the CRT computation.
///
/// # ☢️️ WARNING: HAZARDOUS API ☢️
///
/// Use this function with great care! Raw RSA should never be used without an appropriate padding
/// or signature scheme. See the [module-level documentation][crate::hazmat] for more information.
#[inline]
pub fn rsa_decrypt_and_check<R: CryptoRngCore + ?Sized>(
priv_key: &impl PrivateKeyParts,
rng: Option<&mut R>,
c: &BigUint,
) -> Result<BigUint> {
let m = rsa_decrypt(rng, priv_key, c)?;
// In order to defend against errors in the CRT computation, m^e is
// calculated, which should match the original ciphertext.
let check = rsa_encrypt(priv_key, &m)?;
if c != &check {
return Err(Error::Internal);
}
Ok(m)
}
/// Returns the blinded c, along with the unblinding factor.
fn blind<R: CryptoRngCore, K: PublicKeyParts>(
rng: &mut R,
key: &K,
c: &BigUint,
) -> (BigUint, BigUint) {
// Blinding involves multiplying c by r^e.
// Then the decryption operation performs (m^e * r^e)^d mod n
// which equals mr mod n. The factor of r can then be removed
// by multiplying by the multiplicative inverse of r.
let mut r: BigUint;
let mut ir: Option<BigInt>;
let unblinder;
loop {
r = rng.gen_biguint_below(key.n());
if r.is_zero() {
r = BigUint::one();
}
ir = r.clone().mod_inverse(key.n());
if let Some(ir) = ir {
if let Some(ub) = ir.into_biguint() {
unblinder = ub;
break;
}
}
}
let c = {
let mut rpowe = r.modpow(key.e(), key.n()); // N != 0
let mut c = c * &rpowe;
c %= key.n();
rpowe.zeroize();
c
};
(c, unblinder)
}
/// Given an m and and unblinding factor, unblind the m.
fn unblind(key: &impl PublicKeyParts, m: &BigUint, unblinder: &BigUint) -> BigUint {
(m * unblinder) % key.n()
}
/// The following (deterministic) algorithm also recovers the prime factors `p` and `q` of a modulus `n`, given the
/// public exponent `e` and private exponent `d` using the method described in
/// [NIST 800-56B Appendix C.2](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf).
pub fn recover_primes(n: &BigUint, e: &BigUint, d: &BigUint) -> Result<(BigUint, BigUint)> {
// Check precondition
let two = BigUint::from_u8(2).unwrap();
if e <= &two.pow(16u32) || e >= &two.pow(256u32) {
return Err(Error::InvalidArguments);
}
// 1. Let a = (de 1) × GCD(n 1, de 1).
let one = BigUint::one();
let a = Zeroizing::new((d * e - &one) * (n - &one).gcd(&(d * e - &one)));
// 2. Let m = floor(a /n) and r = a m n, so that a = m n + r and 0 ≤ r < n.
let m = Zeroizing::new(&*a / n);
let r = Zeroizing::new(&*a - &*m * n);
// 3. Let b = ( (n r)/(m + 1) ) + 1; if b is not an integer or b^2 ≤ 4n, then output an error indicator,
// and exit without further processing.
let modulus_check = Zeroizing::new((n - &*r) % (&*m + &one));
if !modulus_check.is_zero() {
return Err(Error::InvalidArguments);
}
let b = Zeroizing::new((n - &*r) / (&*m + &one) + one);
let four = BigUint::from_u8(4).unwrap();
let four_n = Zeroizing::new(n * four);
let b_squared = Zeroizing::new(b.pow(2u32));
if *b_squared <= *four_n {
return Err(Error::InvalidArguments);
}
let b_squared_minus_four_n = Zeroizing::new(&*b_squared - &*four_n);
// 4. Let ϒ be the positive square root of b^2 4n; if ϒ is not an integer,
// then output an error indicator, and exit without further processing.
let y = Zeroizing::new(sqrt((*b_squared_minus_four_n).clone()));
let y_squared = Zeroizing::new(y.pow(2u32));
let sqrt_is_whole_number = y_squared == b_squared_minus_four_n;
if !sqrt_is_whole_number {
return Err(Error::InvalidArguments);
}
let p = (&*b + &*y) / &two;
let q = (&*b - &*y) / two;
Ok((p, q))
}
/// Compute the modulus of a key from its primes.
pub(crate) fn compute_modulus(primes: &[BigUint]) -> BigUint {
primes.iter().product()
}
/// Compute the private exponent from its primes (p and q) and public exponent
/// This uses Euler's totient function
#[inline]
pub(crate) fn compute_private_exponent_euler_totient(
primes: &[BigUint],
exp: &BigUint,
) -> Result<BigUint> {
if primes.len() < 2 {
return Err(Error::InvalidPrime);
}
let mut totient = BigUint::one();
for prime in primes {
totient *= prime - BigUint::one();
}
// NOTE: `mod_inverse` checks if `exp` evenly divides `totient` and returns `None` if so.
// This ensures that `exp` is not a factor of any `(prime - 1)`.
if let Some(d) = exp.mod_inverse(totient) {
Ok(d.to_biguint().unwrap())
} else {
// `exp` evenly divides `totient`
Err(Error::InvalidPrime)
}
}
/// Compute the private exponent from its primes (p and q) and public exponent
///
/// This is using the method defined by
/// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47).
/// (Carmichael function)
///
/// FIPS 186-4 **requires** the private exponent to be less than λ(n), which would
/// make Euler's totiem unreliable.
#[inline]
pub(crate) fn compute_private_exponent_carmicheal(
p: &BigUint,
q: &BigUint,
exp: &BigUint,
) -> Result<BigUint> {
let p1 = p - BigUint::one();
let q1 = q - BigUint::one();
let lcm = p1.lcm(&q1);
if let Some(d) = exp.mod_inverse(lcm) {
Ok(d.to_biguint().unwrap())
} else {
// `exp` evenly divides `lcm`
Err(Error::InvalidPrime)
}
}
#[cfg(test)]
mod tests {
use num_traits::FromPrimitive;
use super::*;
#[test]
fn recover_primes_works() {
let n = BigUint::parse_bytes(b"00d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 16).unwrap();
let e = BigUint::from_u64(65537).unwrap();
let d = BigUint::parse_bytes(b"00c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 16).unwrap();
let p = BigUint::parse_bytes(b"00f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61",16).unwrap();
let q = BigUint::parse_bytes(b"00da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 16).unwrap();
let (mut p1, mut q1) = recover_primes(&n, &e, &d).unwrap();
if p1 < q1 {
std::mem::swap(&mut p1, &mut q1);
}
assert_eq!(p, p1);
assert_eq!(q, q1);
}
}

26
vendor/rsa/src/dummy_rng.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
use rand_core::{CryptoRng, RngCore};
/// This is a dummy RNG for cases when we need a concrete RNG type
/// which does not get used.
#[derive(Copy, Clone)]
pub(crate) struct DummyRng;
impl RngCore for DummyRng {
fn next_u32(&mut self) -> u32 {
unimplemented!();
}
fn next_u64(&mut self) -> u64 {
unimplemented!();
}
fn fill_bytes(&mut self, _: &mut [u8]) {
unimplemented!();
}
fn try_fill_bytes(&mut self, _: &mut [u8]) -> core::result::Result<(), rand_core::Error> {
unimplemented!();
}
}
impl CryptoRng for DummyRng {}

122
vendor/rsa/src/encoding.rs vendored Normal file
View File

@@ -0,0 +1,122 @@
//! PKCS#1 and PKCS#8 encoding support.
//!
//! Note: PKCS#1 support is achieved through a blanket impl of the
//! `pkcs1` crate's traits for types which impl the `pkcs8` crate's traits.
use crate::{
traits::{PrivateKeyParts, PublicKeyParts},
BigUint, RsaPrivateKey, RsaPublicKey,
};
use core::convert::{TryFrom, TryInto};
use pkcs8::{der::Encode, Document, EncodePrivateKey, EncodePublicKey, SecretDocument};
use zeroize::Zeroizing;
/// Verify that the `AlgorithmIdentifier` for a key is correct.
fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> pkcs8::spki::Result<()> {
algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;
if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() {
return Err(pkcs8::spki::Error::KeyMalformed);
}
Ok(())
}
impl TryFrom<pkcs8::PrivateKeyInfo<'_>> for RsaPrivateKey {
type Error = pkcs8::Error;
fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
verify_algorithm_id(&private_key_info.algorithm)?;
let pkcs1_key = pkcs1::RsaPrivateKey::try_from(private_key_info.private_key)?;
// Multi-prime RSA keys not currently supported
if pkcs1_key.version() != pkcs1::Version::TwoPrime {
return Err(pkcs1::Error::Version.into());
}
let n = BigUint::from_bytes_be(pkcs1_key.modulus.as_bytes());
let e = BigUint::from_bytes_be(pkcs1_key.public_exponent.as_bytes());
let d = BigUint::from_bytes_be(pkcs1_key.private_exponent.as_bytes());
let prime1 = BigUint::from_bytes_be(pkcs1_key.prime1.as_bytes());
let prime2 = BigUint::from_bytes_be(pkcs1_key.prime2.as_bytes());
let primes = vec![prime1, prime2];
RsaPrivateKey::from_components(n, e, d, primes).map_err(|_| pkcs8::Error::KeyMalformed)
}
}
impl TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for RsaPublicKey {
type Error = pkcs8::spki::Error;
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
verify_algorithm_id(&spki.algorithm)?;
let pkcs1_key = pkcs1::RsaPublicKey::try_from(
spki.subject_public_key
.as_bytes()
.ok_or(pkcs8::spki::Error::KeyMalformed)?,
)?;
let n = BigUint::from_bytes_be(pkcs1_key.modulus.as_bytes());
let e = BigUint::from_bytes_be(pkcs1_key.public_exponent.as_bytes());
RsaPublicKey::new(n, e).map_err(|_| pkcs8::spki::Error::KeyMalformed)
}
}
impl EncodePrivateKey for RsaPrivateKey {
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
// Check if the key is multi prime
if self.primes.len() > 2 {
return Err(pkcs1::Error::Version.into());
}
let modulus = self.n().to_bytes_be();
let public_exponent = self.e().to_bytes_be();
let private_exponent = Zeroizing::new(self.d().to_bytes_be());
let prime1 = Zeroizing::new(self.primes[0].to_bytes_be());
let prime2 = Zeroizing::new(self.primes[1].to_bytes_be());
let exponent1 = Zeroizing::new((self.d() % (&self.primes[0] - 1u8)).to_bytes_be());
let exponent2 = Zeroizing::new((self.d() % (&self.primes[1] - 1u8)).to_bytes_be());
let coefficient = Zeroizing::new(
self.crt_coefficient()
.ok_or(pkcs1::Error::Crypto)?
.to_bytes_be(),
);
let private_key = pkcs1::RsaPrivateKey {
modulus: pkcs1::UintRef::new(&modulus)?,
public_exponent: pkcs1::UintRef::new(&public_exponent)?,
private_exponent: pkcs1::UintRef::new(&private_exponent)?,
prime1: pkcs1::UintRef::new(&prime1)?,
prime2: pkcs1::UintRef::new(&prime2)?,
exponent1: pkcs1::UintRef::new(&exponent1)?,
exponent2: pkcs1::UintRef::new(&exponent2)?,
coefficient: pkcs1::UintRef::new(&coefficient)?,
other_prime_infos: None,
}
.to_der()?;
pkcs8::PrivateKeyInfo::new(pkcs1::ALGORITHM_ID, private_key.as_ref()).try_into()
}
}
impl EncodePublicKey for RsaPublicKey {
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
let modulus = self.n().to_bytes_be();
let public_exponent = self.e().to_bytes_be();
let subject_public_key = pkcs1::RsaPublicKey {
modulus: pkcs1::UintRef::new(&modulus)?,
public_exponent: pkcs1::UintRef::new(&public_exponent)?,
}
.to_der()?;
pkcs8::SubjectPublicKeyInfoRef {
algorithm: pkcs1::ALGORITHM_ID,
subject_public_key: pkcs8::der::asn1::BitStringRef::new(
0,
subject_public_key.as_ref(),
)?,
}
.try_into()
}
}

126
vendor/rsa/src/errors.rs vendored Normal file
View File

@@ -0,0 +1,126 @@
//! Error types.
/// Alias for [`core::result::Result`] with the `rsa` crate's [`Error`] type.
pub type Result<T> = core::result::Result<T, Error>;
/// Error types
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// Invalid padding scheme.
InvalidPaddingScheme,
/// Decryption error.
Decryption,
/// Verification error.
Verification,
/// Message too long.
MessageTooLong,
/// Input must be hashed.
InputNotHashed,
/// Number of primes must be 2 or greater.
NprimesTooSmall,
/// Too few primes of a given length to generate an RSA key.
TooFewPrimes,
/// Invalid prime value.
InvalidPrime,
/// Invalid modulus.
InvalidModulus,
/// Invalid exponent.
InvalidExponent,
/// Invalid coefficient.
InvalidCoefficient,
/// Modulus too large.
ModulusTooLarge,
/// Public exponent too small.
PublicExponentTooSmall,
/// Public exponent too large.
PublicExponentTooLarge,
/// PKCS#1 error.
Pkcs1(pkcs1::Error),
/// PKCS#8 error.
Pkcs8(pkcs8::Error),
/// Internal error.
Internal,
/// Label too long.
LabelTooLong,
/// Invalid padding length.
InvalidPadLen,
/// Invalid arguments.
InvalidArguments,
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Error::InvalidPaddingScheme => write!(f, "invalid padding scheme"),
Error::Decryption => write!(f, "decryption error"),
Error::Verification => write!(f, "verification error"),
Error::MessageTooLong => write!(f, "message too long"),
Error::InputNotHashed => write!(f, "input must be hashed"),
Error::NprimesTooSmall => write!(f, "nprimes must be >= 2"),
Error::TooFewPrimes => {
write!(f, "too few primes of given length to generate an RSA key")
}
Error::InvalidPrime => write!(f, "invalid prime value"),
Error::InvalidModulus => write!(f, "invalid modulus"),
Error::InvalidExponent => write!(f, "invalid exponent"),
Error::InvalidCoefficient => write!(f, "invalid coefficient"),
Error::ModulusTooLarge => write!(f, "modulus too large"),
Error::PublicExponentTooSmall => write!(f, "public exponent too small"),
Error::PublicExponentTooLarge => write!(f, "public exponent too large"),
Error::Pkcs1(err) => write!(f, "{}", err),
Error::Pkcs8(err) => write!(f, "{}", err),
Error::Internal => write!(f, "internal error"),
Error::LabelTooLong => write!(f, "label too long"),
Error::InvalidPadLen => write!(f, "invalid padding length"),
Error::InvalidArguments => write!(f, "invalid arguments"),
}
}
}
impl From<pkcs1::Error> for Error {
fn from(err: pkcs1::Error) -> Error {
Error::Pkcs1(err)
}
}
impl From<pkcs8::Error> for Error {
fn from(err: pkcs8::Error) -> Error {
Error::Pkcs8(err)
}
}
#[cfg(feature = "std")]
impl From<Error> for signature::Error {
fn from(err: Error) -> Self {
Self::from_source(err)
}
}
#[cfg(not(feature = "std"))]
impl From<Error> for signature::Error {
fn from(_err: Error) -> Self {
Self::new()
}
}

14
vendor/rsa/src/hazmat.rs vendored Normal file
View File

@@ -0,0 +1,14 @@
//! ⚠️ Low-level "hazmat" RSA functions.
//!
//! # ☢️️ WARNING: HAZARDOUS API ☢️
//!
//! This module holds functions that apply RSA's core encryption and decryption
//! primitives to raw data without adding or removing appropriate padding. A
//! well-reviewed padding scheme is crucial to the security of RSA, so there are
//! very few valid uses cases for this API. It's intended to be used for
//! implementing well-reviewed higher-level constructions.
//!
//! We do NOT recommend using it to implement any algorithm which has not
//! received extensive peer review by cryptographers.
pub use crate::algorithms::rsa::{rsa_decrypt, rsa_decrypt_and_check, rsa_encrypt};

859
vendor/rsa/src/key.rs vendored Normal file
View File

@@ -0,0 +1,859 @@
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};
use num_bigint::traits::ModInverse;
use num_bigint::Sign::Plus;
use num_bigint::{BigInt, BigUint};
use num_integer::Integer;
use num_traits::{FromPrimitive, One, ToPrimitive};
use rand_core::CryptoRngCore;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::algorithms::generate::generate_multi_prime_key_with_exp;
use crate::algorithms::rsa::{
compute_modulus, compute_private_exponent_carmicheal, compute_private_exponent_euler_totient,
recover_primes,
};
use crate::dummy_rng::DummyRng;
use crate::errors::{Error, Result};
use crate::traits::{PaddingScheme, PrivateKeyParts, PublicKeyParts, SignatureScheme};
use crate::CrtValue;
/// Represents the public part of an RSA key.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RsaPublicKey {
/// Modulus: product of prime numbers `p` and `q`
n: BigUint,
/// Public exponent: power to which a plaintext message is raised in
/// order to encrypt it.
///
/// Typically 0x10001 (65537)
e: BigUint,
}
/// Represents a whole RSA key, public and private parts.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RsaPrivateKey {
/// Public components of the private key.
pubkey_components: RsaPublicKey,
/// Private exponent
pub(crate) d: BigUint,
/// Prime factors of N, contains >= 2 elements.
pub(crate) primes: Vec<BigUint>,
/// precomputed values to speed up private operations
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) precomputed: Option<PrecomputedValues>,
}
impl Eq for RsaPrivateKey {}
impl PartialEq for RsaPrivateKey {
#[inline]
fn eq(&self, other: &RsaPrivateKey) -> bool {
self.pubkey_components == other.pubkey_components
&& self.d == other.d
&& self.primes == other.primes
}
}
impl AsRef<RsaPublicKey> for RsaPrivateKey {
fn as_ref(&self) -> &RsaPublicKey {
&self.pubkey_components
}
}
impl Hash for RsaPrivateKey {
fn hash<H: Hasher>(&self, state: &mut H) {
// Domain separator for RSA private keys
state.write(b"RsaPrivateKey");
Hash::hash(&self.pubkey_components, state);
}
}
impl Drop for RsaPrivateKey {
fn drop(&mut self) {
self.d.zeroize();
self.primes.zeroize();
self.precomputed.zeroize();
}
}
impl ZeroizeOnDrop for RsaPrivateKey {}
#[derive(Debug, Clone)]
pub(crate) struct PrecomputedValues {
/// D mod (P-1)
pub(crate) dp: BigUint,
/// D mod (Q-1)
pub(crate) dq: BigUint,
/// Q^-1 mod P
pub(crate) qinv: BigInt,
/// CRTValues is used for the 3rd and subsequent primes. Due to a
/// historical accident, the CRT for the first two primes is handled
/// differently in PKCS#1 and interoperability is sufficiently
/// important that we mirror this.
pub(crate) crt_values: Vec<CrtValue>,
}
impl Zeroize for PrecomputedValues {
fn zeroize(&mut self) {
self.dp.zeroize();
self.dq.zeroize();
self.qinv.zeroize();
for val in self.crt_values.iter_mut() {
val.zeroize();
}
self.crt_values.clear();
}
}
impl Drop for PrecomputedValues {
fn drop(&mut self) {
self.zeroize();
}
}
impl From<RsaPrivateKey> for RsaPublicKey {
fn from(private_key: RsaPrivateKey) -> Self {
(&private_key).into()
}
}
impl From<&RsaPrivateKey> for RsaPublicKey {
fn from(private_key: &RsaPrivateKey) -> Self {
let n = private_key.n().clone();
let e = private_key.e().clone();
RsaPublicKey { n, e }
}
}
impl PublicKeyParts for RsaPublicKey {
fn n(&self) -> &BigUint {
&self.n
}
fn e(&self) -> &BigUint {
&self.e
}
}
impl RsaPublicKey {
/// Encrypt the given message.
pub fn encrypt<R: CryptoRngCore, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
msg: &[u8],
) -> Result<Vec<u8>> {
padding.encrypt(rng, self, msg)
}
/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
scheme.verify(self, hashed, sig)
}
}
impl RsaPublicKey {
/// Minimum value of the public exponent `e`.
pub const MIN_PUB_EXPONENT: u64 = 2;
/// Maximum value of the public exponent `e`.
pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
/// Maximum size of the modulus `n` in bits.
pub const MAX_SIZE: usize = 4096;
/// Create a new public key from its components.
///
/// This function accepts public keys with a modulus size up to 4096-bits,
/// i.e. [`RsaPublicKey::MAX_SIZE`].
pub fn new(n: BigUint, e: BigUint) -> Result<Self> {
Self::new_with_max_size(n, e, Self::MAX_SIZE)
}
/// Create a new public key from its components.
pub fn new_with_max_size(n: BigUint, e: BigUint, max_size: usize) -> Result<Self> {
let k = Self { n, e };
check_public_with_max_size(&k, Some(max_size))?;
Ok(k)
}
/// Create a new public key, bypassing checks around the modulus and public
/// exponent size.
///
/// This method is not recommended, and only intended for unusual use cases.
/// Most applications should use [`RsaPublicKey::new`] or
/// [`RsaPublicKey::new_with_max_size`] instead.
pub fn new_unchecked(n: BigUint, e: BigUint) -> Self {
Self { n, e }
}
}
impl PublicKeyParts for RsaPrivateKey {
fn n(&self) -> &BigUint {
&self.pubkey_components.n
}
fn e(&self) -> &BigUint {
&self.pubkey_components.e
}
}
impl RsaPrivateKey {
/// Default exponent for RSA keys.
const EXP: u64 = 65537;
/// Generate a new Rsa key pair of the given bit size using the passed in `rng`.
pub fn new<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<RsaPrivateKey> {
let exp = BigUint::from_u64(Self::EXP).expect("invalid static exponent");
Self::new_with_exp(rng, bit_size, &exp)
}
/// Generate a new RSA key pair of the given bit size and the public exponent
/// using the passed in `rng`.
///
/// Unless you have specific needs, you should use `RsaPrivateKey::new` instead.
pub fn new_with_exp<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
exp: &BigUint,
) -> Result<RsaPrivateKey> {
let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
RsaPrivateKey::from_components(components.n, components.e, components.d, components.primes)
}
/// Constructs an RSA key pair from individual components:
///
/// - `n`: RSA modulus
/// - `e`: public exponent (i.e. encrypting exponent)
/// - `d`: private exponent (i.e. decrypting exponent)
/// - `primes`: prime factors of `n`: typically two primes `p` and `q`. More than two primes can
/// be provided for multiprime RSA, however this is generally not recommended. If no `primes`
/// are provided, a prime factor recovery algorithm will be employed to attempt to recover the
/// factors (as described in [NIST SP 800-56B Revision 2] Appendix C.2). This algorithm only
/// works if there are just two prime factors `p` and `q` (as opposed to multiprime), and `e`
/// is between 2^16 and 2^256.
///
/// [NIST SP 800-56B Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
pub fn from_components(
n: BigUint,
e: BigUint,
d: BigUint,
mut primes: Vec<BigUint>,
) -> Result<RsaPrivateKey> {
if primes.len() < 2 {
if !primes.is_empty() {
return Err(Error::NprimesTooSmall);
}
// Recover `p` and `q` from `d`.
// See method in Appendix C.2: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
let (p, q) = recover_primes(&n, &e, &d)?;
primes.push(p);
primes.push(q);
}
let mut k = RsaPrivateKey {
pubkey_components: RsaPublicKey { n, e },
d,
primes,
precomputed: None,
};
// Always validate the key, to ensure precompute can't fail
k.validate()?;
// precompute when possible, ignore error otherwise.
let _ = k.precompute();
Ok(k)
}
/// Constructs an RSA key pair from its two primes p and q.
///
/// This will rebuild the private exponent and the modulus.
///
/// Private exponent will be rebuilt using the method defined in
/// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47).
pub fn from_p_q(p: BigUint, q: BigUint, public_exponent: BigUint) -> Result<RsaPrivateKey> {
if p == q {
return Err(Error::InvalidPrime);
}
let n = compute_modulus(&[p.clone(), q.clone()]);
let d = compute_private_exponent_carmicheal(&p, &q, &public_exponent)?;
Self::from_components(n, public_exponent, d, vec![p, q])
}
/// Constructs an RSA key pair from its primes.
///
/// This will rebuild the private exponent and the modulus.
pub fn from_primes(primes: Vec<BigUint>, public_exponent: BigUint) -> Result<RsaPrivateKey> {
if primes.len() < 2 {
return Err(Error::NprimesTooSmall);
}
// Makes sure that primes is pairwise unequal.
for (i, prime1) in primes.iter().enumerate() {
for prime2 in primes.iter().take(i) {
if prime1 == prime2 {
return Err(Error::InvalidPrime);
}
}
}
let n = compute_modulus(&primes);
let d = compute_private_exponent_euler_totient(&primes, &public_exponent)?;
Self::from_components(n, public_exponent, d, primes)
}
/// Get the public key from the private key, cloning `n` and `e`.
///
/// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait,
/// but it can occasionally be useful to discard the private information entirely.
pub fn to_public_key(&self) -> RsaPublicKey {
self.pubkey_components.clone()
}
/// Performs some calculations to speed up private key operations.
pub fn precompute(&mut self) -> Result<()> {
if self.precomputed.is_some() {
return Ok(());
}
let dp = &self.d % (&self.primes[0] - BigUint::one());
let dq = &self.d % (&self.primes[1] - BigUint::one());
let qinv = self.primes[1]
.clone()
.mod_inverse(&self.primes[0])
.ok_or(Error::InvalidPrime)?;
let mut r: BigUint = &self.primes[0] * &self.primes[1];
let crt_values: Vec<CrtValue> = {
let mut values = Vec::with_capacity(self.primes.len() - 2);
for prime in &self.primes[2..] {
let res = CrtValue {
exp: BigInt::from_biguint(Plus, &self.d % (prime - BigUint::one())),
r: BigInt::from_biguint(Plus, r.clone()),
coeff: BigInt::from_biguint(
Plus,
r.clone()
.mod_inverse(prime)
.ok_or(Error::InvalidCoefficient)?
.to_biguint()
.unwrap(),
),
};
r *= prime;
values.push(res);
}
values
};
self.precomputed = Some(PrecomputedValues {
dp,
dq,
qinv,
crt_values,
});
Ok(())
}
/// Clears precomputed values by setting to None
pub fn clear_precomputed(&mut self) {
self.precomputed = None;
}
/// Compute CRT coefficient: `(1/q) mod p`.
pub fn crt_coefficient(&self) -> Option<BigUint> {
(&self.primes[1]).mod_inverse(&self.primes[0])?.to_biguint()
}
/// Performs basic sanity checks on the key.
/// Returns `Ok(())` if everything is good, otherwise an appropriate error.
pub fn validate(&self) -> Result<()> {
check_public(self)?;
// Check that Πprimes == n.
let mut m = BigUint::one();
for prime in &self.primes {
// Any primes ≤ 1 will cause divide-by-zero panics later.
if *prime <= BigUint::one() {
return Err(Error::InvalidPrime);
}
m *= prime;
}
if m != self.pubkey_components.n {
return Err(Error::InvalidModulus);
}
// Check that de ≡ 1 mod p-1, for each prime.
// This implies that e is coprime to each p-1 as e has a multiplicative
// inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) =
// exponent(/n). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
// mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
let mut de = self.e().clone();
de *= self.d.clone();
for prime in &self.primes {
let congruence: BigUint = &de % (prime - BigUint::one());
if !congruence.is_one() {
return Err(Error::InvalidExponent);
}
}
Ok(())
}
/// Decrypt the given message.
pub fn decrypt<P: PaddingScheme>(&self, padding: P, ciphertext: &[u8]) -> Result<Vec<u8>> {
padding.decrypt(Option::<&mut DummyRng>::None, self, ciphertext)
}
/// Decrypt the given message.
///
/// Uses `rng` to blind the decryption process.
pub fn decrypt_blinded<R: CryptoRngCore, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
padding.decrypt(Some(rng), self, ciphertext)
}
/// Sign the given digest.
pub fn sign<S: SignatureScheme>(&self, padding: S, digest_in: &[u8]) -> Result<Vec<u8>> {
padding.sign(Option::<&mut DummyRng>::None, self, digest_in)
}
/// Sign the given digest using the provided `rng`, which is used in the
/// following ways depending on the [`SignatureScheme`]:
///
/// - [`Pkcs1v15Sign`][`crate::Pkcs1v15Sign`] padding: uses the RNG
/// to mask the private key operation with random blinding, which helps
/// mitigate sidechannel attacks.
/// - [`Pss`][`crate::Pss`] always requires randomness. Use
/// [`Pss::new`][`crate::Pss::new`] for a standard RSASSA-PSS signature, or
/// [`Pss::new_blinded`][`crate::Pss::new_blinded`] for RSA-BSSA blind
/// signatures.
pub fn sign_with_rng<R: CryptoRngCore, S: SignatureScheme>(
&self,
rng: &mut R,
padding: S,
digest_in: &[u8],
) -> Result<Vec<u8>> {
padding.sign(Some(rng), self, digest_in)
}
}
impl PrivateKeyParts for RsaPrivateKey {
fn d(&self) -> &BigUint {
&self.d
}
fn primes(&self) -> &[BigUint] {
&self.primes
}
fn dp(&self) -> Option<&BigUint> {
self.precomputed.as_ref().map(|p| &p.dp)
}
fn dq(&self) -> Option<&BigUint> {
self.precomputed.as_ref().map(|p| &p.dq)
}
fn qinv(&self) -> Option<&BigInt> {
self.precomputed.as_ref().map(|p| &p.qinv)
}
fn crt_values(&self) -> Option<&[CrtValue]> {
/* for some reason the standard self.precomputed.as_ref().map() doesn't work */
if let Some(p) = &self.precomputed {
Some(p.crt_values.as_slice())
} else {
None
}
}
}
/// Check that the public key is well formed and has an exponent within acceptable bounds.
#[inline]
pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> {
check_public_with_max_size(public_key, None)
}
/// Check that the public key is well formed and has an exponent within acceptable bounds.
#[inline]
fn check_public_with_max_size(
public_key: &impl PublicKeyParts,
max_size: Option<usize>,
) -> Result<()> {
if let Some(max_size) = max_size {
if public_key.n().bits() > max_size {
return Err(Error::ModulusTooLarge);
}
}
let e = public_key
.e()
.to_u64()
.ok_or(Error::PublicExponentTooLarge)?;
if public_key.e() >= public_key.n() || public_key.n().is_even() {
return Err(Error::InvalidModulus);
}
if public_key.e().is_even() {
return Err(Error::InvalidExponent);
}
if e < RsaPublicKey::MIN_PUB_EXPONENT {
return Err(Error::PublicExponentTooSmall);
}
if e > RsaPublicKey::MAX_PUB_EXPONENT {
return Err(Error::PublicExponentTooLarge);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use hex_literal::hex;
use num_traits::{FromPrimitive, ToPrimitive, Zero};
use pkcs8::DecodePrivateKey;
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
#[test]
fn test_from_into() {
let private_key = RsaPrivateKey {
pubkey_components: RsaPublicKey {
n: BigUint::from_u64(100).unwrap(),
e: BigUint::from_u64(200).unwrap(),
},
d: BigUint::from_u64(123).unwrap(),
primes: vec![],
precomputed: None,
};
let public_key: RsaPublicKey = private_key.into();
assert_eq!(public_key.n().to_u64(), Some(100));
assert_eq!(public_key.e().to_u64(), Some(200));
}
fn test_key_basics(private_key: &RsaPrivateKey) {
private_key.validate().expect("invalid private key");
assert!(
private_key.d() < private_key.n(),
"private exponent too large"
);
let pub_key: RsaPublicKey = private_key.clone().into();
let m = BigUint::from_u64(42).expect("invalid 42");
let c = rsa_encrypt(&pub_key, &m).expect("encryption successfull");
let m2 = rsa_decrypt_and_check::<ChaCha8Rng>(private_key, None, &c)
.expect("unable to decrypt without blinding");
assert_eq!(m, m2);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let m3 = rsa_decrypt_and_check(private_key, Some(&mut rng), &c)
.expect("unable to decrypt with blinding");
assert_eq!(m, m3);
}
macro_rules! key_generation {
($name:ident, $multi:expr, $size:expr) => {
#[test]
fn $name() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let exp = BigUint::from_u64(RsaPrivateKey::EXP).expect("invalid static exponent");
for _ in 0..10 {
let components =
generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap();
let private_key = RsaPrivateKey::from_components(
components.n,
components.e,
components.d,
components.primes,
)
.unwrap();
assert_eq!(private_key.n().bits(), $size);
test_key_basics(&private_key);
}
}
};
}
key_generation!(key_generation_128, 2, 128);
key_generation!(key_generation_1024, 2, 1024);
key_generation!(key_generation_multi_3_256, 3, 256);
key_generation!(key_generation_multi_4_64, 4, 64);
key_generation!(key_generation_multi_5_64, 5, 64);
key_generation!(key_generation_multi_8_576, 8, 576);
key_generation!(key_generation_multi_16_1024, 16, 1024);
#[test]
fn test_negative_decryption_value() {
let private_key = RsaPrivateKey::from_components(
BigUint::from_bytes_le(&[
99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
]),
BigUint::from_bytes_le(&[1, 0, 1]),
BigUint::from_bytes_le(&[
81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
]),
vec![
BigUint::from_bytes_le(&[105, 101, 60, 173, 19, 153, 3, 192]),
BigUint::from_bytes_le(&[235, 65, 160, 134, 32, 136, 6, 241]),
],
)
.unwrap();
for _ in 0..1000 {
test_key_basics(&private_key);
}
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use serde_test::{assert_tokens, Token};
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
let priv_tokens = [
Token::Struct {
name: "RsaPrivateKey",
len: 3,
},
Token::Str("pubkey_components"),
Token::Struct {
name: "RsaPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(3814409919),
Token::U32(3429654832),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
Token::Str("d"),
Token::Seq { len: Some(2) },
Token::U32(1482162201),
Token::U32(1675500232),
Token::SeqEnd,
Token::Str("primes"),
Token::Seq { len: Some(2) },
Token::Seq { len: Some(1) },
Token::U32(4133289821),
Token::SeqEnd,
Token::Seq { len: Some(1) },
Token::U32(3563808971),
Token::SeqEnd,
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&priv_key, &priv_tokens);
let priv_tokens = [
Token::Struct {
name: "RsaPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(3814409919),
Token::U32(3429654832),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&RsaPublicKey::from(priv_key), &priv_tokens);
}
#[test]
fn invalid_coeff_private_key_regression() {
use base64ct::{Base64, Encoding};
let n = Base64::decode_vec("wC8GyQvTCZOK+iiBR5fGQCmzRCTWX9TQ3aRG5gGFk0wB6EFoLMAyEEqeG3gS8xhAm2rSWYx9kKufvNat3iWlbSRVqkcbpVAYlj2vTrpqDpJl+6u+zxFYoUEBevlJJkAhl8EuCccOA30fVpcfRvXPTtvRd3yFT9E9EwZljtgSI02w7gZwg7VIxaGeajh5Euz6ZVQZ+qNRKgXrRC7gPRqVyI6Dt0Jc+Su5KBGNn0QcPDzOahWha1ieaeMkFisZ9mdpsJoZ4tw5eicLaUomKzALHXQVt+/rcZSrCd6/7uUo11B/CYBM4UfSpwXaL88J9AE6A5++no9hmJzaF2LLp+Qwx4yY3j9TDutxSAjsraxxJOGZ3XyA9nG++Ybt3cxZ5fP7ROjxCfROBmVv5dYn0O9OBIqYeCH6QraNpZMadlLNIhyMv8Y+P3r5l/PaK4VJaEi5pPosnEPawp0W0yZDzmjk2z1LthaRx0aZVrAjlH0Rb/6goLUQ9qu1xsDtQVVpN4A89ZUmtTWORnnJr0+595eHHxssd2gpzqf4bPjNITdAEuOCCtpvyi4ls23zwuzryUYjcUOEnsXNQ+DrZpLKxdtsD/qNV/j1hfeyBoPllC3cV+6bcGOFcVGbjYqb+Kw1b0+jL69RSKQqgmS+qYqr8c48nDRxyq3QXhR8qtzUwBFSLVk=").unwrap();
let e = Base64::decode_vec("AQAB").unwrap();
let d = Base64::decode_vec("qQazSQ+FRN7nVK1bRsROMRB8AmsDwLVEHivlz1V3Td2Dr+oW3YUMgxedhztML1IdQJPq/ad6qErJ6yRFNySVIjDaxzBTOEoB1eHa1btOnBJWb8rVvvjaorixvJ6Tn3i4EuhsvVy9DoR1k4rGj3qSIiFjUVvLRDAbLyhpGgEfsr0Z577yJmTC5E8JLRMOKX8Tmxsk3jPVpsgd65Hu1s8S/ZmabwuHCf9SkdMeY/1bd/9i7BqqJeeDLE4B5x1xcC3z3scqDUTzqGO+vZPhjgprPDRlBamVwgenhr7KwCn8iaLamFinRVwOAag8BeBqOJj7lURiOsKQa9FIX1kdFUS1QMQxgtPycLjkbvCJjriqT7zWKsmJ7l8YLs6Wmm9/+QJRwNCEVdMTXKfCP1cJjudaiskEQThfUldtgu8gUDNYbQ/Filb2eKfiX4h1TiMxZqUZHVZyb9nShbQoXJ3vj/MGVF0QM8TxhXM8r2Lv9gDYU5t9nQlUMLhs0jVjai48jHABbFNyH3sEcOmJOIwJrCXw1dzG7AotwyaEVUHOmL04TffmwCFfnyrLjbFgnyOeoyIIBYjcY7QFRm/9nupXMTH5hZ2qrHfCJIp0KK4tNBdQqmnHapFl5l6Le1s4qBS5bEIzjitobLvAFm9abPlDGfxmY6mlrMK4+nytwF9Ct7wc1AE=").unwrap();
let primes = vec![
Base64::decode_vec("9kQWEAzsbzOcdPa+s5wFfw4XDd7bB1q9foZ31b1+TNjGNxbSBCFlDF1q98vwpV6nM8bWDh/wtbNoETSQDgpEnYOQ26LWEw6YY1+q1Q2GGEFceYUf+Myk8/vTc8TN6Zw0bKZBWy10Qo8h7xk4JpzuI7NcxvjJYTkS9aErFxi3vVH0aiZC0tmfaCqr8a2rJxyVwqreRpOjwAWrotMsf2wGsF4ofx5ScoFy5GB5fJkkdOrW1LyTvZAUCX3cstPr19+TNC5zZOk7WzZatnCkN5H5WzalWtZuu0oVL205KPOa3R8V2yv5e6fm0v5fTmqSuvjmaMJLXCN4QJkmIzojO99ckQ==").unwrap(),
Base64::decode_vec("x8exdMjVA2CiI+Thx7loHtVcevoeE2sZ7btRVAvmBqo+lkHwxb7FHRnWvuj6eJSlD2f0T50EewIhhiW3R9BmktCk7hXjbSCnC1u9Oxc1IAUm/7azRqyfCMx43XhLxpD+xkBCpWkKDLxGczsRwTuaP3lKS3bSdBrNlGmdblubvVBIq4YZ2vXVlnYtza0cS+dgCK7BGTqUsrCUd/ZbIvwcwZkZtpkhj1KQfto9X/0OMurBzAqbkeq1cyRHXHkOfN/qbUIIRqr9Ii7Eswf9Vk8xp2O1Nt8nzcYS9PFD12M5eyaeFEkEYfpNMNGuTzp/31oqVjbpoCxS6vuWAZyADxhISQ==").unwrap(),
Base64::decode_vec("is7d0LY4HoXszlC2NO7gejkq7XqL4p1W6hZJPYTNx+r37t1CC2n3Vvzg6kNdpRixDhIpXVTLjN9O7UO/XuqSumYKJIKoP52eb4Tg+a3hw5Iz2Zsb5lUTNSLgkQSBPAf71LHxbL82JL4g1nBUog8ae60BwnVArThKY4EwlJguGNw09BAU4lwf6csDl/nX2vfVwiAloYpeZkHL+L8m+bueGZM5KE2jEz+7ztZCI+T+E5i69rZEYDjx0lfLKlEhQlCW3HbCPELqXgNJJkRfi6MP9kXa9lSfnZmoT081RMvqonB/FUa4HOcKyCrw9XZEtnbNCIdbitfDVEX+pSSD7596wQ==").unwrap(),
Base64::decode_vec("GPs0injugfycacaeIP5jMa/WX55VEnKLDHom4k6WlfDF4L4gIGoJdekcPEUfxOI5faKvHyFwRP1wObkPoRBDM0qZxRfBl4zEtpvjHrd5MibSyJkM8+J0BIKk/nSjbRIGeb3hV5O56PvGB3S0dKhCUnuVObiC+ne7izplsD4OTG70l1Yud33UFntyoMxrxGYLUSqhBMmZfHquJg4NOWOzKNY/K+EcHDLj1Kjvkcgv9Vf7ocsVxvpFdD9uGPceQ6kwRDdEl6mb+6FDgWuXVyqR9+904oanEIkbJ7vfkthagLbEf57dyG6nJlqh5FBZWxGIR72YGypPuAh7qnnqXXjY2Q==").unwrap(),
Base64::decode_vec("CUWC+hRWOT421kwRllgVjy6FYv6jQUcgDNHeAiYZnf5HjS9iK2ki7v8G5dL/0f+Yf+NhE/4q8w4m8go51hACrVpP1p8GJDjiT09+RsOzITsHwl+ceEKoe56ZW6iDHBLlrNw5/MtcYhKpjNU9KJ2udm5J/c9iislcjgckrZG2IB8ADgXHMEByZ5DgaMl4AKZ1Gx8/q6KftTvmOT5rNTMLi76VN5KWQcDWK/DqXiOiZHM7Nr4dX4me3XeRgABJyNR8Fqxj3N1+HrYLe/zs7LOaK0++F9Ul3tLelhrhsvLxei3oCZkF9A/foD3on3luYA+1cRcxWpSY3h2J4/22+yo4+Q==").unwrap(),
];
let res = RsaPrivateKey::from_components(
BigUint::from_bytes_be(&n),
BigUint::from_bytes_be(&e),
BigUint::from_bytes_be(&d),
primes.iter().map(|p| BigUint::from_bytes_be(p)).collect(),
);
assert_eq!(res, Err(Error::InvalidModulus));
}
#[test]
fn reject_oversized_private_key() {
// -----BEGIN PUBLIC KEY-----
// MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAkMBiB8qsNVXAsJR6Xoto
// H1r2rtZl/xzUK2tIfy99aPE489u+5tLxCQhQf+a89158vSDpr2/xwgK8w9u0Xpu2
// m7XRKjVMS0Y6UIINFoeTc87rVXT92Scr47kNVcGmSFXez4BSDpS+LKpWwXN+0AQu
// +cmcfdtsx2862iEbqQvq4PwKGQJOdOR0yldH8O4yeJK/buvIOXRHjb++vtQND/xi
// bFGAcd9WJqvaOG7tclhbZ277mbO6ER+y9Lj7AyO8ywybWqNeHaVPHMysPhT7HUWI
// 17m59i1OpuVwwEnvzDQQEUf9d5hUmkLYb5qQzuf6Ddnx/04QJCKAgkhyr9CXgnV6
// vEZ3PKtpicCHRxk7eqTEmgBlgwqH5vflRFV1iywQMXJnuRhzWOQaXl/vb8v4HIvF
// 4TatEZKqfzpbyScLIiYbPEAhHXKdZMd2zY8hkSbicifePApAZmuNpAxxJDZzphh7
// r4lD6t8MPT/RUAdtrZfihqaBhduFI6YeVIy6emg05M6YWvlUyer7nYGaPRS1JqD4
// 0v7xOtme5I8Qw6APiFPXhTqBK3occr7TgGb3V3lpC8Eq+esNHrji98R1fITkFXJW
// KdFcTWjBghPxiobUzMCFUrPIDJcWXeBzrARAryU+hXjEiFfzluXrps0B7RJQ/rLD
// LXeTn4vovUeHQVHa7YfoyWMy9pfqeVC+56LBK7SEIAvL0I3lrq5vIv+ZIuOAdbVg
// JiRy8DneCOk2LP3RnA8M0HSevYW93DiC+4h/l4ntjjiOfi6yRVOZ8WbVyXZ/83j4
// 6+pGWgvi0uMyb+btgOXjBQv7bGqdyHMc5Lqk5bF7ExETx51vKQMYCV4351caS6aX
// q16lYZATHgbTADEAZHdroDMJB+HMQaze9O6qU5ZO8wxxAjw89xry0dnoOQD/yA4H
// 7CRCo9vVDpV2hqIvHY9RI2T7cek28kmQpKvNvvK+ovmM138dHKViWULHk0fBRt7m
// 4wQ+tiL2PmJ/Tr8g1gVhM6S9D1XdE9z0KeDnODCWn1Q8sx2G2ah4ynnYQURDWcwO
// McAoP6bdJ7cCt+4F2tEsMPf4S/EwlnjvuNoQjvztxCPahYe9EnyggtQXyHJveIn7
// gDJsP6b93VB6x4QbLy5ch4DUhqDWginuKVeo7CTgDkq03j/IEaS1BHwreSDQceny
// +bYWONwV+4TMpGytKOHvU5288kmHbyZHdXuaXk8LLqbnqr30fa6Cbp4llCi9sH5a
// Kmi5jxQfVTe+elkMs7oVsLsVgkZS6NqPcOuEckAFijNqG223+IJoqvifCzO5Bdcs
// JTOLE+YaUYc8LUJwIaPykgcXmtMvQjeT8MCQ3aAlzkHfDpSvvICrXtqbGiaKolU6
// mQIDAQAB
// -----END PUBLIC KEY-----
let n = BigUint::from_bytes_be(&hex!(
"
90c06207caac3555c0b0947a5e8b681f5af6aed665ff1cd42b6b487f2f7d68f1
38f3dbbee6d2f10908507fe6bcf75e7cbd20e9af6ff1c202bcc3dbb45e9bb69b
b5d12a354c4b463a50820d16879373ceeb5574fdd9272be3b90d55c1a64855de
cf80520e94be2caa56c1737ed0042ef9c99c7ddb6cc76f3ada211ba90beae0fc
0a19024e74e474ca5747f0ee327892bf6eebc83974478dbfbebed40d0ffc626c
518071df5626abda386eed72585b676efb99b3ba111fb2f4b8fb0323bccb0c9b
5aa35e1da54f1cccac3e14fb1d4588d7b9b9f62d4ea6e570c049efcc34101147
fd7798549a42d86f9a90cee7fa0dd9f1ff4e10242280824872afd09782757abc
46773cab6989c08747193b7aa4c49a0065830a87e6f7e54455758b2c10317267
b9187358e41a5e5fef6fcbf81c8bc5e136ad1192aa7f3a5bc9270b22261b3c40
211d729d64c776cd8f219126e27227de3c0a40666b8da40c71243673a6187baf
8943eadf0c3d3fd150076dad97e286a68185db8523a61e548cba7a6834e4ce98
5af954c9eafb9d819a3d14b526a0f8d2fef13ad99ee48f10c3a00f8853d7853a
812b7a1c72bed38066f75779690bc12af9eb0d1eb8e2f7c4757c84e415725629
d15c4d68c18213f18a86d4ccc08552b3c80c97165de073ac0440af253e8578c4
8857f396e5eba6cd01ed1250feb2c32d77939f8be8bd47874151daed87e8c963
32f697ea7950bee7a2c12bb484200bcbd08de5aeae6f22ff9922e38075b56026
2472f039de08e9362cfdd19c0f0cd0749ebd85bddc3882fb887f9789ed8e388e
7e2eb2455399f166d5c9767ff378f8ebea465a0be2d2e3326fe6ed80e5e3050b
fb6c6a9dc8731ce4baa4e5b17b131113c79d6f290318095e37e7571a4ba697ab
5ea56190131e06d300310064776ba0330907e1cc41acdef4eeaa53964ef30c71
023c3cf71af2d1d9e83900ffc80e07ec2442a3dbd50e957686a22f1d8f512364
fb71e936f24990a4abcdbef2bea2f98cd77f1d1ca5625942c79347c146dee6e3
043eb622f63e627f4ebf20d6056133a4bd0f55dd13dcf429e0e73830969f543c
b31d86d9a878ca79d841444359cc0e31c0283fa6dd27b702b7ee05dad12c30f7
f84bf1309678efb8da108efcedc423da8587bd127ca082d417c8726f7889fb80
326c3fa6fddd507ac7841b2f2e5c8780d486a0d68229ee2957a8ec24e00e4ab4
de3fc811a4b5047c2b7920d071e9f2f9b61638dc15fb84cca46cad28e1ef539d
bcf249876f2647757b9a5e4f0b2ea6e7aabdf47dae826e9e259428bdb07e5a2a
68b98f141f5537be7a590cb3ba15b0bb15824652e8da8f70eb847240058a336a
1b6db7f88268aaf89f0b33b905d72c25338b13e61a51873c2d427021a3f29207
179ad32f423793f0c090dda025ce41df0e94afbc80ab5eda9b1a268aa2553a99"
));
let e = BigUint::from_u64(65537).unwrap();
assert_eq!(
RsaPublicKey::new(n, e).err().unwrap(),
Error::ModulusTooLarge
);
}
#[test]
fn build_key_from_primes() {
const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/pkcs8/rsa2048-priv.der");
let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
assert_eq!(ref_key.validate(), Ok(()));
let primes = ref_key.primes().to_vec();
let exp = ref_key.e().clone();
let key =
RsaPrivateKey::from_primes(primes, exp).expect("failed to import key from primes");
assert_eq!(key.validate(), Ok(()));
assert_eq!(key.n(), ref_key.n());
assert_eq!(key.dp(), ref_key.dp());
assert_eq!(key.dq(), ref_key.dq());
assert_eq!(key.d(), ref_key.d());
}
#[test]
fn build_key_from_p_q() {
const RSA_2048_SP800_PRIV_DER: &[u8] =
include_bytes!("../tests/examples/pkcs8/rsa2048-sp800-56b-priv.der");
let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_SP800_PRIV_DER).unwrap();
assert_eq!(ref_key.validate(), Ok(()));
let primes = ref_key.primes().to_vec();
let exp = ref_key.e().clone();
let key = RsaPrivateKey::from_p_q(primes[0].clone(), primes[1].clone(), exp)
.expect("failed to import key from primes");
assert_eq!(key.validate(), Ok(()));
assert_eq!(key.n(), ref_key.n());
assert_eq!(key.dp(), ref_key.dp());
assert_eq!(key.dq(), ref_key.dq());
assert_eq!(key.d(), ref_key.d());
}
#[test]
fn test_key_invalid_primes() {
let e = RsaPrivateKey::from_components(
BigUint::from_u64(239).unwrap(),
BigUint::from_u64(185).unwrap(),
BigUint::zero(),
vec![
BigUint::from_u64(1).unwrap(),
BigUint::from_u64(239).unwrap(),
],
)
.unwrap_err();
assert_eq!(e, Error::InvalidPrime);
}
}

255
vendor/rsa/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,255 @@
#![cfg_attr(not(test), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![warn(missing_docs)]
//! # Supported algorithms
//!
//! This crate supports several schemes described in [RFC8017]:
//!
//! - [OAEP encryption scheme](#oaep-encryption)
//! - [PKCS#1 v1.5 encryption scheme](#pkcs1-v15-encryption)
//! - [PKCS#1 v1.5 signature scheme](#pkcs1-v15-signatures)
//! - [PSS signature scheme](#pss-signatures)
//!
//! These schemes are described below.
//!
//! # Usage
//!
//! ## OAEP encryption
//!
//! Note: requires `sha2` feature of `rsa` crate is enabled.
//!
#![cfg_attr(feature = "sha2", doc = "```")]
#![cfg_attr(not(feature = "sha2"), doc = "```ignore")]
//! use rsa::{RsaPrivateKey, RsaPublicKey, Oaep, sha2::Sha256};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let public_key = RsaPublicKey::from(&private_key);
//!
//! // Encrypt
//! let data = b"hello world";
//! let padding = Oaep::new::<Sha256>();
//! let enc_data = public_key.encrypt(&mut rng, padding, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let padding = Oaep::new::<Sha256>();
//! let dec_data = private_key.decrypt(padding, &enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
//! ## PKCS#1 v1.5 encryption
//! ```
//! use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let public_key = RsaPublicKey::from(&private_key);
//!
//! // Encrypt
//! let data = b"hello world";
//! let enc_data = public_key.encrypt(&mut rng, Pkcs1v15Encrypt, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let dec_data = private_key.decrypt(Pkcs1v15Encrypt, &enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
//! ## PKCS#1 v1.5 signatures
//!
//! Note: requires `sha2` feature of `rsa` crate is enabled.
//!
#![cfg_attr(feature = "sha2", doc = "```")]
#![cfg_attr(not(feature = "sha2"), doc = "```ignore")]
//! use rsa::RsaPrivateKey;
//! use rsa::pkcs1v15::{SigningKey, VerifyingKey};
//! use rsa::signature::{Keypair, RandomizedSigner, SignatureEncoding, Verifier};
//! use rsa::sha2::{Digest, Sha256};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let signing_key = SigningKey::<Sha256>::new(private_key);
//! let verifying_key = signing_key.verifying_key();
//!
//! // Sign
//! let data = b"hello world";
//! let signature = signing_key.sign_with_rng(&mut rng, data);
//! assert_ne!(signature.to_bytes().as_ref(), data.as_slice());
//!
//! // Verify
//! verifying_key.verify(data, &signature).expect("failed to verify");
//! ```
//!
//! ## PSS signatures
//!
//! Note: requires `sha2` feature of `rsa` crate is enabled.
//!
#![cfg_attr(feature = "sha2", doc = "```")]
#![cfg_attr(not(feature = "sha2"), doc = "```ignore")]
//! use rsa::RsaPrivateKey;
//! use rsa::pss::{BlindedSigningKey, VerifyingKey};
//! use rsa::signature::{Keypair,RandomizedSigner, SignatureEncoding, Verifier};
//! use rsa::sha2::{Digest, Sha256};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let signing_key = BlindedSigningKey::<Sha256>::new(private_key);
//! let verifying_key = signing_key.verifying_key();
//!
//! // Sign
//! let data = b"hello world";
//! let signature = signing_key.sign_with_rng(&mut rng, data);
//! assert_ne!(signature.to_bytes().as_ref(), data);
//!
//! // Verify
//! verifying_key.verify(data, &signature).expect("failed to verify");
//! ```
//!
//! ## PKCS#1 RSA Key Encoding
//!
//! PKCS#1 supports a legacy format for encoding RSA keys as binary (DER) or
//! text (PEM) data.
//!
//! You can recognize PEM encoded PKCS#1 keys because they have "RSA * KEY" in
//! the type label, e.g.:
//!
//! ```text
//! -----BEGIN RSA PRIVATE KEY-----
//! ```
//!
//! Most modern applications use the newer PKCS#8 format instead (see below).
//!
//! The following traits can be used to decode/encode [`RsaPrivateKey`] and
//! [`RsaPublicKey`] as PKCS#1. Note that [`pkcs1`] is re-exported from the
//! toplevel of the `rsa` crate:
//!
//! - [`pkcs1::DecodeRsaPrivateKey`]: decode RSA private keys from PKCS#1
//! - [`pkcs1::EncodeRsaPrivateKey`]: encode RSA private keys to PKCS#1
//! - [`pkcs1::DecodeRsaPublicKey`]: decode RSA public keys from PKCS#1
//! - [`pkcs1::EncodeRsaPublicKey`]: encode RSA public keys to PKCS#1
//!
//! ### Example
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[cfg(all(feature = "pem", feature = "std"))]
//! # {
//! use rsa::{RsaPublicKey, pkcs1::DecodeRsaPublicKey};
//!
//! let pem = "-----BEGIN RSA PUBLIC KEY-----
//! MIIBCgKCAQEAtsQsUV8QpqrygsY+2+JCQ6Fw8/omM71IM2N/R8pPbzbgOl0p78MZ
//! GsgPOQ2HSznjD0FPzsH8oO2B5Uftws04LHb2HJAYlz25+lN5cqfHAfa3fgmC38Ff
//! wBkn7l582UtPWZ/wcBOnyCgb3yLcvJrXyrt8QxHJgvWO23ITrUVYszImbXQ67YGS
//! 0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0NfFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J
//! 9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejIn04APPKIjpMyQdnWlby7rNyQtE4+CV+j
//! cFjqJbE/Xilcvqxt6DirjFCvYeKYl1uHLwIDAQAB
//! -----END RSA PUBLIC KEY-----";
//!
//! let public_key = RsaPublicKey::from_pkcs1_pem(pem)?;
//! # }
//! # Ok(())
//! # }
//! ```
//!
//! ## PKCS#8 RSA Key Encoding
//!
//! PKCS#8 is a private key format with support for multiple algorithms.
//! Like PKCS#1, it can be encoded as binary (DER) or text (PEM).
//!
//! You can recognize PEM encoded PKCS#8 keys because they *don't* have
//! an algorithm name in the type label, e.g.:
//!
//! ```text
//! -----BEGIN PRIVATE KEY-----
//! ```
//!
//! The following traits can be used to decode/encode [`RsaPrivateKey`] and
//! [`RsaPublicKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the
//! toplevel of the `rsa` crate:
//!
//! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8
//! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8
//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8
//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8
//!
//! ### Example
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[cfg(all(feature = "pem", feature = "std"))]
//! # {
//! use rsa::{RsaPublicKey, pkcs8::DecodePublicKey};
//!
//! let pem = "-----BEGIN PUBLIC KEY-----
//! MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtsQsUV8QpqrygsY+2+JC
//! Q6Fw8/omM71IM2N/R8pPbzbgOl0p78MZGsgPOQ2HSznjD0FPzsH8oO2B5Uftws04
//! LHb2HJAYlz25+lN5cqfHAfa3fgmC38FfwBkn7l582UtPWZ/wcBOnyCgb3yLcvJrX
//! yrt8QxHJgvWO23ITrUVYszImbXQ67YGS0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0N
//! fFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejI
//! n04APPKIjpMyQdnWlby7rNyQtE4+CV+jcFjqJbE/Xilcvqxt6DirjFCvYeKYl1uH
//! LwIDAQAB
//! -----END PUBLIC KEY-----";
//!
//! let public_key = RsaPublicKey::from_public_key_pem(pem)?;
//! # }
//! # Ok(())
//! # }
//! ```
//!
//! [RFC8017]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
//!
// TODO(tarcieri): figure out why rustdoc isn't rendering these links correctly
//! [`pkcs8::DecodePublicKey`]: https://docs.rs/pkcs8/latest/pkcs8/trait.DecodePublicKey.html
//! [`pkcs8::EncodePublicKey`]: https://docs.rs/pkcs8/latest/pkcs8/trait.EncodePublicKey.html
#[cfg(doctest)]
pub struct ReadmeDoctests;
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
pub use num_bigint::BigUint;
pub use rand_core;
pub use signature;
mod algorithms;
pub mod errors;
pub mod oaep;
pub mod pkcs1v15;
pub mod pss;
pub mod traits;
mod dummy_rng;
mod encoding;
mod key;
pub use pkcs1;
pub use pkcs8;
#[cfg(feature = "sha2")]
pub use sha2;
pub use crate::{
errors::{Error, Result},
key::{RsaPrivateKey, RsaPublicKey},
oaep::Oaep,
pkcs1v15::{Pkcs1v15Encrypt, Pkcs1v15Sign},
pss::Pss,
traits::keys::CrtValue,
};
#[cfg(feature = "hazmat")]
pub mod hazmat;

588
vendor/rsa/src/oaep.rs vendored Normal file
View File

@@ -0,0 +1,588 @@
//! Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#oaep-encryption).
mod decrypting_key;
mod encrypting_key;
pub use self::{decrypting_key::DecryptingKey, encrypting_key::EncryptingKey};
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt;
use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use rand_core::CryptoRngCore;
use zeroize::Zeroizing;
use crate::algorithms::oaep::*;
use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::errors::{Error, Result};
use crate::key::{self, RsaPrivateKey, RsaPublicKey};
use crate::traits::{PaddingScheme, PublicKeyParts};
/// Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
///
/// - `digest` is used to hash the label. The maximum possible plaintext length is `m = k - 2 * h_len - 2`,
/// where `k` is the size of the RSA modulus.
/// - `mgf_digest` specifies the hash function that is used in the [MGF1](https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.2).
/// - `label` is optional data that can be associated with the message.
///
/// The two hash functions can, but don't need to be the same.
///
/// A prominent example is the [`AndroidKeyStore`](https://developer.android.com/guide/topics/security/cryptography#oaep-mgf1-digest).
/// It uses SHA-1 for `mgf_digest` and a user-chosen SHA flavour for `digest`.
pub struct Oaep {
/// Digest type to use.
pub digest: Box<dyn DynDigest + Send + Sync>,
/// Digest to use for Mask Generation Function (MGF).
pub mgf_digest: Box<dyn DynDigest + Send + Sync>,
/// Optional label.
pub label: Option<String>,
}
impl Oaep {
/// Create a new OAEP `PaddingScheme`, using `T` as the hash function for both the default (empty) label and for MGF1.
///
/// # Example
/// ```
/// use sha1::Sha1;
/// use sha2::Sha256;
/// use rsa::{BigUint, RsaPublicKey, Oaep, };
/// use base64ct::{Base64, Encoding};
///
/// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
/// let e = Base64::decode_vec("AQAB").unwrap();
///
/// let mut rng = rand::thread_rng(); // rand@0.8
/// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap();
/// let padding = Oaep::new::<Sha256>();
/// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap();
/// ```
pub fn new<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(T::new()),
label: None,
}
}
/// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for both the label and for MGF1.
pub fn new_with_label<T: 'static + Digest + DynDigest + Send + Sync, S: AsRef<str>>(
label: S,
) -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(T::new()),
label: Some(label.as_ref().to_string()),
}
}
/// Create a new OAEP `PaddingScheme`, using `T` as the hash function for the default (empty) label, and `U` as the hash function for MGF1.
/// If a label is needed use `PaddingScheme::new_oaep_with_label` or `PaddingScheme::new_oaep_with_mgf_hash_with_label`.
///
/// # Example
/// ```
/// use sha1::Sha1;
/// use sha2::Sha256;
/// use rsa::{BigUint, RsaPublicKey, Oaep, };
/// use base64ct::{Base64, Encoding};
///
/// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
/// let e = Base64::decode_vec("AQAB").unwrap();
///
/// let mut rng = rand::thread_rng(); // rand@0.8
/// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap();
/// let padding = Oaep::new_with_mgf_hash::<Sha256, Sha1>();
/// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap();
/// ```
pub fn new_with_mgf_hash<
T: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
>() -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(U::new()),
label: None,
}
}
/// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for the label, and `U` as the hash function for MGF1.
pub fn new_with_mgf_hash_and_label<
T: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
S: AsRef<str>,
>(
label: S,
) -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(U::new()),
label: Some(label.as_ref().to_string()),
}
}
}
impl PaddingScheme for Oaep {
fn decrypt<Rng: CryptoRngCore>(
mut self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(
rng,
priv_key,
ciphertext,
&mut *self.digest,
&mut *self.mgf_digest,
self.label,
)
}
fn encrypt<Rng: CryptoRngCore>(
mut self,
rng: &mut Rng,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(
rng,
pub_key,
msg,
&mut *self.digest,
&mut *self.mgf_digest,
self.label,
)
}
}
impl fmt::Debug for Oaep {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OAEP")
.field("digest", &"...")
.field("mgf_digest", &"...")
.field("label", &self.label)
.finish()
}
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
pub_key: &RsaPublicKey,
msg: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let em = oaep_encrypt(rng, msg, digest, mgf_digest, label, pub_key.size())?;
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
fn encrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutputReset>(
rng: &mut R,
pub_key: &RsaPublicKey,
msg: &[u8],
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let em = oaep_encrypt_digest::<_, D, MGD>(rng, msg, label, pub_key.size())?;
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from [PKCS#1 OAEP].
///
/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn decrypt<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(priv_key)?;
if ciphertext.len() != priv_key.size() {
return Err(Error::Decryption);
}
let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?;
let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
oaep_decrypt(&mut em, digest, mgf_digest, label, priv_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from [PKCS#1 OAEP].
///
/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn decrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutputReset>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(priv_key)?;
if ciphertext.len() != priv_key.size() {
return Err(Error::Decryption);
}
let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?;
let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
oaep_decrypt_digest::<D, MGD>(&mut em, label, priv_key.size())
}
#[cfg(test)]
mod tests {
use crate::key::{RsaPrivateKey, RsaPublicKey};
use crate::oaep::{DecryptingKey, EncryptingKey, Oaep};
use crate::traits::PublicKeyParts;
use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};
use alloc::string::String;
use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use num_traits::FromPrimitive;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha8Rng,
};
use sha1::Sha1;
use sha2::{Sha224, Sha256, Sha384, Sha512};
use sha3::{Sha3_256, Sha3_384, Sha3_512};
fn get_private_key() -> RsaPrivateKey {
// -----BEGIN RSA PRIVATE KEY-----
// MIIEpAIBAAKCAQEA05e4TZikwmE47RtpWoEG6tkdVTvwYEG2LT/cUKBB4iK49FKW
// icG4LF5xVU9d1p+i9LYVjPDb61eBGg/DJ+HyjnT+dNO8Fmweq9wbi1e5NMqL5bAL
// TymXW8yZrK9BW1m7KKZ4K7QaLDwpdrPBjbre9i8AxrsiZkAJUJbAzGDSL+fvmH11
// xqgbENlr8pICivEQ3HzBu8Q9Iq2rN5oM1dgHjMeA/1zWIJ3qNMkiz3hPdxfkKNdb
// WuyP8w5fAUFRB2bi4KuNRzyE6HELK5gifD2wlTN600UvGeK5v7zN2BSKv2d2+lUn
// debnWVbkUimuWpxGlJurHmIvDkj1ZSSoTtNIOwIDAQABAoIBAQDE5wxokWLJTGYI
// KBkbUrTYOSEV30hqmtvoMeRY1zlYMg3Bt1VFbpNwHpcC12+wuS+Q4B0f4kgVMoH+
// eaqXY6kvrmnY1+zRRN4p+hNb0U+Vc+NJ5FAx47dpgvWDADgmxVLomjl8Gga9IWNI
// hjDZLowrtkPXq+9wDaldaFyUFImkb1S1MW9itdLDp/G70TTLNzU6RGg/3J2V02RY
// 3iL2xEBX/nSgpDbEMI9z9NpC81xHrBanE41IOvyR5B3DoRJzguDA9RGbAiG0/GOd
// a5w4F3pt6bUm69iMONeYLAf5ig79h31Qiq4nW5RpFcAuLhEG0XXXTsZ3f16A0SwF
// PZx74eNBAoGBAPgnu/OkGHfHzFmuv0LtSynDLe/LjtloY9WwkKBaiTDdYkohydz5
// g4Vo/foN9luEYqXyrJE9bFb5dVMr2OePsHvUBcqZpIS89Z8Bm73cs5M/K85wYwC0
// 97EQEgxd+QGBWQZ8NdowYaVshjWlK1QnOzEnG0MR8Hld9gIeY1XhpC5hAoGBANpI
// F84Aid028q3mo/9BDHPsNL8bT2vaOEMb/t4RzvH39u+nDl+AY6Ox9uFylv+xX+76
// CRKgMluNH9ZaVZ5xe1uWHsNFBy4OxSA9A0QdKa9NZAVKBFB0EM8dp457YRnZCexm
// 5q1iW/mVsnmks8W+fYlc18W5xMSX/ecwkW/NtOQbAoGAHabpz4AhKFbodSLrWbzv
// CUt4NroVFKdjnoodjfujfwJFF2SYMV5jN9LG3lVCxca43ulzc1tqka33Nfv8TBcg
// WHuKQZ5ASVgm5VwU1wgDMSoQOve07MWy/yZTccTc1zA0ihDXgn3bfR/NnaVh2wlh
// CkuI92eyW1494hztc7qlmqECgYEA1zenyOQ9ChDIW/ABGIahaZamNxsNRrDFMl3j
// AD+cxHSRU59qC32CQH8ShRy/huHzTaPX2DZ9EEln76fnrS4Ey7uLH0rrFl1XvT6K
// /timJgLvMEvXTx/xBtUdRN2fUqXtI9odbSyCtOYFL+zVl44HJq2UzY4pVRDrNcxs
// SUkQJqsCgYBSaNfPBzR5rrstLtTdZrjImRW1LRQeDEky9WsMDtCTYUGJTsTSfVO8
// hkU82MpbRVBFIYx+GWIJwcZRcC7OCQoV48vMJllxMAAjqG/p00rVJ+nvA7et/nNu
// BoB0er/UmDm4Ly/97EO9A0PKMOE5YbMq9s3t3RlWcsdrU7dvw+p2+A==
// -----END RSA PRIVATE KEY-----
RsaPrivateKey::from_components(
BigUint::parse_bytes(b"00d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 16).unwrap(),
BigUint::from_u64(65537).unwrap(),
BigUint::parse_bytes(b"00c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 16).unwrap(),
vec![
BigUint::parse_bytes(b"00f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61",16).unwrap(),
BigUint::parse_bytes(b"00da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 16).unwrap()
],
).unwrap()
}
#[test]
fn test_encrypt_decrypt_oaep() {
let priv_key = get_private_key();
do_test_encrypt_decrypt_oaep::<Sha1>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha224>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha256>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha384>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha512>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha3_256>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha3_384>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha3_512>(&priv_key);
do_test_oaep_with_different_hashes::<Sha1, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha224, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha512, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha3_256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha3_384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha3_512, Sha1>(&priv_key);
}
fn get_label(rng: &mut ChaCha8Rng) -> Option<String> {
const GEN_ASCII_STR_CHARSET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789=+";
let mut buf = [0u8; 32];
rng.fill_bytes(&mut buf);
if buf[0] < (1 << 7) {
for v in buf.iter_mut() {
*v = GEN_ASCII_STR_CHARSET[(*v >> 2) as usize];
}
Some(core::str::from_utf8(&buf).unwrap().to_string())
} else {
None
}
}
fn do_test_encrypt_decrypt_oaep<D: 'static + Digest + DynDigest + Send + Sync>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = prk.size();
for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);
let pub_key: RsaPublicKey = prk.into();
let ciphertext = if let Some(ref label) = label {
let padding = Oaep::new_with_label::<D, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = Oaep::new::<D>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
};
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);
let padding = if let Some(ref label) = label {
Oaep::new_with_label::<D, _>(label)
} else {
Oaep::new::<D>()
};
let plaintext = if blind {
prk.decrypt(padding, &ciphertext).unwrap()
} else {
prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
};
assert_eq!(input, plaintext);
}
}
fn do_test_oaep_with_different_hashes<
D: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = prk.size();
for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);
let pub_key: RsaPublicKey = prk.into();
let ciphertext = if let Some(ref label) = label {
let padding = Oaep::new_with_mgf_hash_and_label::<D, U, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = Oaep::new_with_mgf_hash::<D, U>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
};
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);
let padding = if let Some(ref label) = label {
Oaep::new_with_mgf_hash_and_label::<D, U, _>(label)
} else {
Oaep::new_with_mgf_hash::<D, U>()
};
let plaintext = if blind {
prk.decrypt(padding, &ciphertext).unwrap()
} else {
prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
};
assert_eq!(input, plaintext);
}
}
#[test]
fn test_decrypt_oaep_invalid_hash() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let pub_key: RsaPublicKey = (&priv_key).into();
let ciphertext = pub_key
.encrypt(&mut rng, Oaep::new::<Sha1>(), "a_plain_text".as_bytes())
.unwrap();
assert!(
priv_key
.decrypt_blinded(
&mut rng,
Oaep::new_with_label::<Sha1, _>("label"),
&ciphertext,
)
.is_err(),
"decrypt should have failed on hash verification"
);
}
#[test]
fn test_encrypt_decrypt_oaep_traits() {
let priv_key = get_private_key();
do_test_encrypt_decrypt_oaep_traits::<Sha1>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha224>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha256>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha384>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha512>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha3_256>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha3_384>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha3_512>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha1, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha224, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha512, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha3_256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha3_384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha3_512, Sha1>(&priv_key);
}
fn do_test_encrypt_decrypt_oaep_traits<D: Digest + FixedOutputReset>(prk: &RsaPrivateKey) {
do_test_oaep_with_different_hashes_traits::<D, D>(prk);
}
fn do_test_oaep_with_different_hashes_traits<D: Digest, MGD: Digest + FixedOutputReset>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = prk.size();
for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);
let pub_key: RsaPublicKey = prk.into();
let ciphertext = if let Some(ref label) = label {
let encrypting_key =
EncryptingKey::<D, MGD>::new_with_label(pub_key, label.clone());
encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
} else {
let encrypting_key = EncryptingKey::<D, MGD>::new(pub_key);
encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
};
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);
let decrypting_key = if let Some(ref label) = label {
DecryptingKey::<D, MGD>::new_with_label(prk.clone(), label.clone())
} else {
DecryptingKey::<D, MGD>::new(prk.clone())
};
let plaintext = if blind {
decrypting_key.decrypt(&ciphertext).unwrap()
} else {
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.unwrap()
};
assert_eq!(input, plaintext);
}
}
#[test]
fn test_decrypt_oaep_invalid_hash_traits() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let pub_key: RsaPublicKey = (&priv_key).into();
let encrypting_key = EncryptingKey::<Sha1>::new(pub_key);
let decrypting_key = DecryptingKey::<Sha1>::new_with_label(priv_key, "label");
let ciphertext = encrypting_key
.encrypt_with_rng(&mut rng, "a_plain_text".as_bytes())
.unwrap();
assert!(
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.is_err(),
"decrypt should have failed on hash verification"
);
}
}

96
vendor/rsa/src/oaep/decrypting_key.rs vendored Normal file
View File

@@ -0,0 +1,96 @@
use super::decrypt_digest;
use crate::{
dummy_rng::DummyRng,
traits::{Decryptor, RandomizedDecryptor},
Result, RsaPrivateKey,
};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use rand_core::CryptoRngCore;
use zeroize::ZeroizeOnDrop;
/// Decryption key for PKCS#1 v1.5 decryption as described in [RFC8017 § 7.1].
///
/// [RFC8017 § 7.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[derive(Debug, Clone)]
pub struct DecryptingKey<D, MGD = D>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
inner: RsaPrivateKey,
label: Option<String>,
phantom: PhantomData<D>,
mg_phantom: PhantomData<MGD>,
}
impl<D, MGD> DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPrivateKey) -> Self {
Self {
inner: key,
label: None,
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
/// Create a new verifying key from an RSA public key using provided label
pub fn new_with_label<S: AsRef<str>>(key: RsaPrivateKey, label: S) -> Self {
Self {
inner: key,
label: Some(label.as_ref().to_string()),
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
}
impl<D, MGD> Decryptor for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
decrypt_digest::<DummyRng, D, MGD>(
None,
&self.inner,
ciphertext,
self.label.as_ref().cloned(),
)
}
}
impl<D, MGD> RandomizedDecryptor for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn decrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt_digest::<_, D, MGD>(
Some(rng),
&self.inner,
ciphertext,
self.label.as_ref().cloned(),
)
}
}
impl<D, MGD> ZeroizeOnDrop for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
}

64
vendor/rsa/src/oaep/encrypting_key.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
use super::encrypt_digest;
use crate::{traits::RandomizedEncryptor, Result, RsaPublicKey};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use rand_core::CryptoRngCore;
/// Encryption key for PKCS#1 v1.5 encryption as described in [RFC8017 § 7.1].
///
/// [RFC8017 § 7.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[derive(Debug, Clone)]
pub struct EncryptingKey<D, MGD = D>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
inner: RsaPublicKey,
label: Option<String>,
phantom: PhantomData<D>,
mg_phantom: PhantomData<MGD>,
}
impl<D, MGD> EncryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPublicKey) -> Self {
Self {
inner: key,
label: None,
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
/// Create a new verifying key from an RSA public key using provided label
pub fn new_with_label<S: AsRef<str>>(key: RsaPublicKey, label: S) -> Self {
Self {
inner: key,
label: Some(label.as_ref().to_string()),
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
}
impl<D, MGD> RandomizedEncryptor for EncryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn encrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt_digest::<_, D, MGD>(rng, &self.inner, msg, self.label.as_ref().cloned())
}
}

708
vendor/rsa/src/pkcs1v15.rs vendored Normal file
View File

@@ -0,0 +1,708 @@
//! PKCS#1 v1.5 support as described in [RFC8017 § 8.2].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pkcs1-v15-signatures).
//!
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
mod decrypting_key;
mod encrypting_key;
mod signature;
mod signing_key;
mod verifying_key;
pub use self::{
decrypting_key::DecryptingKey, encrypting_key::EncryptingKey, signature::Signature,
signing_key::SigningKey, verifying_key::VerifyingKey,
};
use alloc::{boxed::Box, vec::Vec};
use core::fmt::Debug;
use digest::Digest;
use num_bigint::BigUint;
use pkcs8::AssociatedOid;
use rand_core::CryptoRngCore;
use zeroize::Zeroizing;
use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
use crate::algorithms::pkcs1v15::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::errors::{Error, Result};
use crate::key::{self, RsaPrivateKey, RsaPublicKey};
use crate::traits::{PaddingScheme, PublicKeyParts, SignatureScheme};
/// Encryption using PKCS#1 v1.5 padding.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Pkcs1v15Encrypt;
impl PaddingScheme for Pkcs1v15Encrypt {
fn decrypt<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(rng, priv_key, ciphertext)
}
fn encrypt<Rng: CryptoRngCore>(
self,
rng: &mut Rng,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(rng, pub_key, msg)
}
}
/// `RSASSA-PKCS1-v1_5`: digital signatures using PKCS#1 v1.5 padding.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pkcs1v15Sign {
/// Length of hash to use.
pub hash_len: Option<usize>,
/// Prefix.
pub prefix: Box<[u8]>,
}
impl Pkcs1v15Sign {
/// Create new PKCS#1 v1.5 padding for the given digest.
///
/// The digest must have an [`AssociatedOid`]. Make sure to enable the `oid`
/// feature of the relevant digest crate.
pub fn new<D>() -> Self
where
D: Digest + AssociatedOid,
{
Self {
hash_len: Some(<D as Digest>::output_size()),
prefix: pkcs1v15_generate_prefix::<D>().into_boxed_slice(),
}
}
/// Create new PKCS#1 v1.5 padding for computing an unprefixed signature.
///
/// This sets `hash_len` to `None` and uses an empty `prefix`.
pub fn new_unprefixed() -> Self {
Self {
hash_len: None,
prefix: Box::new([]),
}
}
/// Create new PKCS#1 v1.5 padding for computing an unprefixed signature.
///
/// This sets `hash_len` to `None` and uses an empty `prefix`.
#[deprecated(since = "0.9.0", note = "use Pkcs1v15Sign::new_unprefixed instead")]
pub fn new_raw() -> Self {
Self::new_unprefixed()
}
}
impl SignatureScheme for Pkcs1v15Sign {
fn sign<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
) -> Result<Vec<u8>> {
if let Some(hash_len) = self.hash_len {
if hashed.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
sign(rng, priv_key, &self.prefix, hashed)
}
fn verify(self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()> {
if let Some(hash_len) = self.hash_len {
if hashed.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
verify(
pub_key,
self.prefix.as_ref(),
hashed,
&BigUint::from_bytes_be(sig),
sig.len(),
)
}
}
/// Encrypts the given message with RSA and the padding
/// scheme from PKCS#1 v1.5. The message must be no longer than the
/// length of the public modulus minus 11 bytes.
#[inline]
fn encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let em = pkcs1v15_encrypt_pad(rng, msg, pub_key.size())?;
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
///
/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key. See
/// `decrypt_session_key` for a way of solving this problem.
#[inline]
fn decrypt<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
key::check_public(priv_key)?;
let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?;
let em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
pkcs1v15_encrypt_unpad(em, priv_key.size())
}
/// Calculates the signature of hashed using
/// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. Note that `hashed` must
/// be the result of hashing the input message using the given hash
/// function. If hash is `None`, hashed is signed directly. This isn't
/// advisable except for interoperability.
///
/// If `rng` is not `None` then RSA blinding will be used to avoid timing
/// side-channel attacks.
///
/// This function is deterministic. Thus, if the set of possible
/// messages is small, an attacker may be able to build a map from
/// messages to signatures and identify the signed messages. As ever,
/// signatures provide authenticity, not confidentiality.
#[inline]
fn sign<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
prefix: &[u8],
hashed: &[u8],
) -> Result<Vec<u8>> {
let em = pkcs1v15_sign_pad(prefix, hashed, priv_key.size())?;
uint_to_zeroizing_be_pad(
rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(&em))?,
priv_key.size(),
)
}
/// Verifies an RSA PKCS#1 v1.5 signature.
#[inline]
fn verify(
pub_key: &RsaPublicKey,
prefix: &[u8],
hashed: &[u8],
sig: &BigUint,
sig_len: usize,
) -> Result<()> {
if sig >= pub_key.n() || sig_len != pub_key.size() {
return Err(Error::Verification);
}
let em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
pkcs1v15_sign_unpad(prefix, hashed, &em, pub_key.size())
}
mod oid {
use const_oid::ObjectIdentifier;
/// A trait which associates an RSA-specific OID with a type.
pub trait RsaSignatureAssociatedOid {
/// The OID associated with this type.
const OID: ObjectIdentifier;
}
#[cfg(feature = "sha1")]
impl RsaSignatureAssociatedOid for sha1::Sha1 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.5");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha224 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.14");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha256 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha384 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.12");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha512 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.13");
}
}
pub use oid::RsaSignatureAssociatedOid;
#[cfg(test)]
mod tests {
use super::*;
use ::signature::{
hazmat::{PrehashSigner, PrehashVerifier},
DigestSigner, DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner,
SignatureEncoding, Signer, Verifier,
};
use base64ct::{Base64, Encoding};
use hex_literal::hex;
use num_bigint::BigUint;
use num_traits::FromPrimitive;
use num_traits::Num;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha8Rng,
};
use sha1::{Digest, Sha1};
use sha2::Sha256;
use sha3::Sha3_256;
use crate::traits::{
Decryptor, EncryptingKeypair, PublicKeyParts, RandomizedDecryptor, RandomizedEncryptor,
};
use crate::{RsaPrivateKey, RsaPublicKey};
fn get_private_key() -> RsaPrivateKey {
// In order to generate new test vectors you'll need the PEM form of this key:
// -----BEGIN RSA PRIVATE KEY-----
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
// -----END RSA PRIVATE KEY-----
RsaPrivateKey::from_components(
BigUint::from_str_radix("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077", 10).unwrap(),
BigUint::from_u64(65537).unwrap(),
BigUint::from_str_radix("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861", 10).unwrap(),
vec![
BigUint::from_str_radix("98920366548084643601728869055592650835572950932266967461790948584315647051443",10).unwrap(),
BigUint::from_str_radix("94560208308847015747498523884063394671606671904944666360068158221458669711639", 10).unwrap()
],
).unwrap()
}
#[test]
fn test_decrypt_pkcs1v15() {
let priv_key = get_private_key();
let tests = [[
"gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
"x",
], [
"Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
"testing.",
], [
"arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
"testing.\n",
], [
"WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
"01234567890123456789012345678901234567890123456789012",
]];
for test in &tests {
let out = priv_key
.decrypt(Pkcs1v15Encrypt, &Base64::decode_vec(test[0]).unwrap())
.unwrap();
assert_eq!(out, test[1].as_bytes());
}
}
#[test]
fn test_encrypt_decrypt_pkcs1v15() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let k = priv_key.size();
for i in 1..100 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let pub_key: RsaPublicKey = priv_key.clone().into();
let ciphertext = encrypt(&mut rng, &pub_key, &input).unwrap();
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1u32 << 31);
let blinder = if blind { Some(&mut rng) } else { None };
let plaintext = decrypt(blinder, &priv_key, &ciphertext).unwrap();
assert_eq!(input, plaintext);
}
}
#[test]
fn test_decrypt_pkcs1v15_traits() {
let priv_key = get_private_key();
let decrypting_key = DecryptingKey::new(priv_key);
let tests = [[
"gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
"x",
], [
"Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
"testing.",
], [
"arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
"testing.\n",
], [
"WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
"01234567890123456789012345678901234567890123456789012",
]];
for test in &tests {
let out = decrypting_key
.decrypt(&Base64::decode_vec(test[0]).unwrap())
.unwrap();
assert_eq!(out, test[1].as_bytes());
}
}
#[test]
fn test_encrypt_decrypt_pkcs1v15_traits() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let k = priv_key.size();
let decrypting_key = DecryptingKey::new(priv_key);
for i in 1..100 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let encrypting_key = decrypting_key.encrypting_key();
let ciphertext = encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap();
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1u32 << 31);
let plaintext = if blind {
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.unwrap()
} else {
decrypting_key.decrypt(&ciphertext).unwrap()
};
assert_eq!(input, plaintext);
}
}
#[test]
fn test_sign_pkcs1v15() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];
for (text, expected) in &tests {
let digest = Sha1::digest(text.as_bytes()).to_vec();
let out = priv_key.sign(Pkcs1v15Sign::new::<Sha1>(), &digest).unwrap();
assert_ne!(out, digest);
assert_eq!(out, expected);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let out2 = priv_key
.sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha1>(), &digest)
.unwrap();
assert_eq!(out2, expected);
}
}
#[test]
fn test_sign_pkcs1v15_signer() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];
let signing_key = SigningKey::<Sha1>::new(priv_key);
for (text, expected) in &tests {
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())
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_sign_pkcs1v15_signer_sha2_256() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"
),
)];
let signing_key = SigningKey::<Sha256>::new(priv_key);
for (text, expected) in &tests {
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())
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_sign_pkcs1v15_signer_sha3_256() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"55e9fba3354dfb51d2c8111794ea552c86afc2cab154652c03324df8c2c51ba7"
"2ff7c14de59a6f9ba50d90c13a7537cc3011948369f1f0ec4a49d21eb7e723f9"
),
)];
let signing_key = SigningKey::<Sha3_256>::new(priv_key);
for (text, expected) in &tests {
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())
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_sign_pkcs1v15_digest_signer() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];
let signing_key = SigningKey::new(priv_key);
for (text, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
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);
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)
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_verify_pkcs1v15() {
let priv_key = get_private_key();
let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
for (text, sig, expected) in &tests {
let digest = Sha1::digest(text.as_bytes()).to_vec();
let result = pub_key.verify(Pkcs1v15Sign::new::<Sha1>(), &digest, sig);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pkcs1v15_signer() {
let priv_key = get_private_key();
let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
for (text, sig, expected) in &tests {
let result = verifying_key.verify(
text.as_bytes(),
&Signature::try_from(sig.as_slice()).unwrap(),
);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pkcs1v15_digest_signer() {
let priv_key = get_private_key();
let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::new(pub_key);
for (text, sig, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let result =
verifying_key.verify_digest(digest, &Signature::try_from(sig.as_slice()).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_unpadded_signature() {
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
let priv_key = get_private_key();
let sig = priv_key.sign(Pkcs1v15Sign::new_unprefixed(), msg).unwrap();
assert_eq!(expected_sig, sig);
let pub_key: RsaPublicKey = priv_key.into();
pub_key
.verify(Pkcs1v15Sign::new_unprefixed(), msg, &sig)
.expect("failed to verify");
}
#[test]
fn test_unpadded_signature_hazmat() {
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
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")
.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.as_slice()).unwrap())
.expect("failed to verify");
}
}

View File

@@ -0,0 +1,51 @@
use super::{decrypt, EncryptingKey};
use crate::{
dummy_rng::DummyRng,
traits::{Decryptor, EncryptingKeypair, RandomizedDecryptor},
Result, RsaPrivateKey,
};
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
use zeroize::ZeroizeOnDrop;
/// Decryption key for PKCS#1 v1.5 decryption as described in [RFC8017 § 7.2].
///
/// [RFC8017 § 7.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.2
#[derive(Debug, Clone)]
pub struct DecryptingKey {
inner: RsaPrivateKey,
}
impl DecryptingKey {
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPrivateKey) -> Self {
Self { inner: key }
}
}
impl Decryptor for DecryptingKey {
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
decrypt::<DummyRng>(None, &self.inner, ciphertext)
}
}
impl RandomizedDecryptor for DecryptingKey {
fn decrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(Some(rng), &self.inner, ciphertext)
}
}
impl EncryptingKeypair for DecryptingKey {
type EncryptingKey = EncryptingKey;
fn encrypting_key(&self) -> EncryptingKey {
EncryptingKey {
inner: self.inner.clone().into(),
}
}
}
impl ZeroizeOnDrop for DecryptingKey {}

View File

@@ -0,0 +1,29 @@
use super::encrypt;
use crate::{traits::RandomizedEncryptor, Result, RsaPublicKey};
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
/// Encryption key for PKCS#1 v1.5 encryption as described in [RFC8017 § 7.2].
///
/// [RFC8017 § 7.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.2
#[derive(Debug, Clone)]
pub struct EncryptingKey {
pub(super) inner: RsaPublicKey,
}
impl EncryptingKey {
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPublicKey) -> Self {
Self { inner: key }
}
}
impl RandomizedEncryptor for EncryptingKey {
fn encrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(rng, &self.inner, msg)
}
}

80
vendor/rsa/src/pkcs1v15/signature.rs vendored Normal file
View File

@@ -0,0 +1,80 @@
pub use ::signature::SignatureEncoding;
use spki::{
der::{asn1::BitString, Result as DerResult},
SignatureBitStringEncoding,
};
use crate::algorithms::pad::uint_to_be_pad;
use alloc::{boxed::Box, string::ToString};
use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
use num_bigint::BigUint;
/// `RSASSA-PKCS1-v1_5` signatures as described in [RFC8017 § 8.2].
///
/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
#[derive(Clone, PartialEq, Eq)]
pub struct Signature {
pub(super) inner: BigUint,
pub(super) len: usize,
}
impl SignatureEncoding for Signature {
type Repr = Box<[u8]>;
}
impl SignatureBitStringEncoding for Signature {
fn to_bitstring(&self) -> DerResult<BitString> {
BitString::new(0, self.to_vec())
}
}
impl TryFrom<&[u8]> for Signature {
type Error = signature::Error;
fn try_from(bytes: &[u8]) -> signature::Result<Self> {
Ok(Self {
inner: BigUint::from_bytes_be(bytes),
len: bytes.len(),
})
}
}
impl From<Signature> for Box<[u8]> {
fn from(signature: Signature) -> Box<[u8]> {
uint_to_be_pad(signature.inner, signature.len)
.expect("RSASSA-PKCS1-v1_5 length invariants should've been enforced")
.into_boxed_slice()
}
}
impl Debug for Signature {
fn fmt(&self, fmt: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
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.to_bytes().iter() {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl UpperHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
for byte in self.to_bytes().iter() {
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}
impl Display for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}", self)
}
}

255
vendor/rsa/src/pkcs1v15/signing_key.rs vendored Normal file
View File

@@ -0,0 +1,255 @@
use super::{oid, pkcs1v15_generate_prefix, sign, Signature, VerifyingKey};
use crate::{dummy_rng::DummyRng, Result, RsaPrivateKey};
use alloc::vec::Vec;
use core::marker::PhantomData;
use digest::Digest;
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
SignatureAlgorithmIdentifier,
},
AssociatedOid, EncodePrivateKey, SecretDocument,
};
use rand_core::CryptoRngCore;
use signature::{
hazmat::PrehashSigner, DigestSigner, Keypair, RandomizedDigestSigner, RandomizedSigner, Signer,
};
use zeroize::ZeroizeOnDrop;
/// Signing key for `RSASSA-PKCS1-v1_5` signatures as described in [RFC8017 § 8.2].
///
/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
#[derive(Debug, Clone)]
pub struct SigningKey<D>
where
D: Digest,
{
inner: RsaPrivateKey,
prefix: Vec<u8>,
phantom: PhantomData<D>,
}
impl<D> SigningKey<D>
where
D: Digest + AssociatedOid,
{
/// Create a new signing key with a prefix for the digest `D`.
pub fn new(key: RsaPrivateKey) -> Self {
Self {
inner: key,
prefix: pkcs1v15_generate_prefix::<D>(),
phantom: Default::default(),
}
}
/// Generate a new signing key with a prefix for the digest `D`.
pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
prefix: pkcs1v15_generate_prefix::<D>(),
phantom: Default::default(),
})
}
/// Create a new signing key with a prefix for the digest `D`.
#[deprecated(since = "0.9.0", note = "use SigningKey::new instead")]
pub fn new_with_prefix(key: RsaPrivateKey) -> Self {
Self::new(key)
}
/// Generate a new signing key with a prefix for the digest `D`.
#[deprecated(since = "0.9.0", note = "use SigningKey::random instead")]
pub fn random_with_prefix<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
) -> Result<Self> {
Self::random(rng, bit_size)
}
}
impl<D> SigningKey<D>
where
D: Digest,
{
/// Create a new signing key from the give RSA private key with an empty prefix.
///
/// ## Note: unprefixed signatures are uncommon
///
/// In most cases you'll want to use [`SigningKey::new`].
pub fn new_unprefixed(key: RsaPrivateKey) -> Self {
Self {
inner: key,
prefix: Vec::new(),
phantom: Default::default(),
}
}
/// Generate a new signing key with an empty prefix.
pub fn random_unprefixed<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
prefix: Vec::new(),
phantom: Default::default(),
})
}
}
//
// `*Signer` trait impls
//
impl<D> DigestSigner<D, Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_digest(&self, digest: D) -> signature::Result<Signature> {
sign::<DummyRng>(None, &self.inner, &self.prefix, &digest.finalize())?
.as_slice()
.try_into()
}
}
impl<D> PrehashSigner<Signature> for SigningKey<D>
where
D: Digest,
{
fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
sign::<DummyRng>(None, &self.inner, &self.prefix, prehash)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_digest_with_rng(
&self,
rng: &mut impl CryptoRngCore,
digest: D,
) -> signature::Result<Signature> {
sign(Some(rng), &self.inner, &self.prefix, &digest.finalize())?
.as_slice()
.try_into()
}
}
impl<D> RandomizedSigner<Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_with_rng(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> signature::Result<Signature> {
sign(Some(rng), &self.inner, &self.prefix, &D::digest(msg))?
.as_slice()
.try_into()
}
}
impl<D> Signer<Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
sign::<DummyRng>(None, &self.inner, &self.prefix, &D::digest(msg))?
.as_slice()
.try_into()
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPrivateKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
impl<D> EncodePrivateKey for SigningKey<D>
where
D: Digest,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
self.inner.to_pkcs8_der()
}
}
impl<D> From<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn from(key: RsaPrivateKey) -> Self {
Self::new_unprefixed(key)
}
}
impl<D> From<SigningKey<D>> for RsaPrivateKey
where
D: Digest,
{
fn from(key: SigningKey<D>) -> Self {
key.inner
}
}
impl<D> Keypair for SigningKey<D>
where
D: Digest,
{
type VerifyingKey = VerifyingKey<D>;
fn verifying_key(&self) -> Self::VerifyingKey {
VerifyingKey {
inner: self.inner.to_public_key(),
prefix: self.prefix.clone(),
phantom: Default::default(),
}
}
}
impl<D> SignatureAlgorithmIdentifier for SigningKey<D>
where
D: Digest + oid::RsaSignatureAssociatedOid,
{
type Params = AnyRef<'static>;
const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
AlgorithmIdentifierRef {
oid: D::OID,
parameters: Some(AnyRef::NULL),
};
}
impl<D> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<D>
where
D: Digest + AssociatedOid,
{
type Error = pkcs8::Error;
fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
RsaPrivateKey::try_from(private_key_info).map(Self::new)
}
}
impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}

203
vendor/rsa/src/pkcs1v15/verifying_key.rs vendored Normal file
View File

@@ -0,0 +1,203 @@
use super::{oid, pkcs1v15_generate_prefix, verify, Signature};
use crate::RsaPublicKey;
use alloc::vec::Vec;
use core::marker::PhantomData;
use digest::Digest;
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
SignatureAlgorithmIdentifier,
},
AssociatedOid, Document, EncodePublicKey,
};
use signature::{hazmat::PrehashVerifier, DigestVerifier, Verifier};
/// Verifying key for `RSASSA-PKCS1-v1_5` signatures as described in [RFC8017 § 8.2].
///
/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
#[derive(Debug)]
pub struct VerifyingKey<D>
where
D: Digest,
{
pub(super) inner: RsaPublicKey,
pub(super) prefix: Vec<u8>,
pub(super) phantom: PhantomData<D>,
}
impl<D> VerifyingKey<D>
where
D: Digest + AssociatedOid,
{
/// Create a new verifying key with a prefix for the digest `D`.
pub fn new(key: RsaPublicKey) -> Self {
Self {
inner: key,
prefix: pkcs1v15_generate_prefix::<D>(),
phantom: Default::default(),
}
}
/// Create a new verifying key with a prefix for the digest `D`.
#[deprecated(since = "0.9.0", note = "use VerifyingKey::new instead")]
pub fn new_with_prefix(key: RsaPublicKey) -> Self {
Self::new(key)
}
}
impl<D> VerifyingKey<D>
where
D: Digest,
{
/// Create a new verifying key from an RSA public key with an empty prefix.
///
/// ## Note: unprefixed signatures are uncommon
///
/// In most cases you'll want to use [`VerifyingKey::new`] instead.
pub fn new_unprefixed(key: RsaPublicKey) -> Self {
Self {
inner: key,
prefix: Vec::new(),
phantom: Default::default(),
}
}
}
//
// `*Verifier` trait impls
//
impl<D> DigestVerifier<D, Signature> for VerifyingKey<D>
where
D: Digest,
{
fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> {
verify(
&self.inner,
&self.prefix,
&digest.finalize(),
&signature.inner,
signature.len,
)
.map_err(|e| e.into())
}
}
impl<D> PrehashVerifier<Signature> for VerifyingKey<D>
where
D: Digest,
{
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> {
verify(
&self.inner,
&self.prefix,
prehash,
&signature.inner,
signature.len,
)
.map_err(|e| e.into())
}
}
impl<D> Verifier<Signature> for VerifyingKey<D>
where
D: Digest,
{
fn verify(&self, msg: &[u8], signature: &Signature) -> signature::Result<()> {
verify(
&self.inner,
&self.prefix.clone(),
&D::digest(msg),
&signature.inner,
signature.len,
)
.map_err(|e| e.into())
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPublicKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for VerifyingKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
// Implemented manually so we don't have to bind D with Clone
impl<D> Clone for VerifyingKey<D>
where
D: Digest,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
prefix: self.prefix.clone(),
phantom: Default::default(),
}
}
}
impl<D> EncodePublicKey for VerifyingKey<D>
where
D: Digest,
{
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
self.inner.to_public_key_der()
}
}
impl<D> From<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn from(key: RsaPublicKey) -> Self {
Self::new_unprefixed(key)
}
}
impl<D> From<VerifyingKey<D>> for RsaPublicKey
where
D: Digest,
{
fn from(key: VerifyingKey<D>) -> Self {
key.inner
}
}
impl<D> SignatureAlgorithmIdentifier for VerifyingKey<D>
where
D: Digest + oid::RsaSignatureAssociatedOid,
{
type Params = AnyRef<'static>;
const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
AlgorithmIdentifierRef {
oid: D::OID,
parameters: Some(AnyRef::NULL),
};
}
impl<D> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<D>
where
D: Digest + AssociatedOid,
{
type Error = pkcs8::spki::Error;
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
RsaPublicKey::try_from(spki).map(Self::new)
}
}

613
vendor/rsa/src/pss.rs vendored Normal file
View File

@@ -0,0 +1,613 @@
//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
//!
//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pss-signatures).
//!
//! [Probabilistic Signature Scheme]: https://en.wikipedia.org/wiki/Probabilistic_signature_scheme
//! [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
mod blinded_signing_key;
mod signature;
mod signing_key;
mod verifying_key;
pub use self::{
blinded_signing_key::BlindedSigningKey, signature::Signature, signing_key::SigningKey,
verifying_key::VerifyingKey,
};
use alloc::{boxed::Box, vec::Vec};
use core::fmt::{self, Debug};
use const_oid::{AssociatedOid, ObjectIdentifier};
use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use pkcs1::RsaPssParams;
use pkcs8::spki::{der::Any, AlgorithmIdentifierOwned};
use rand_core::CryptoRngCore;
use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
use crate::algorithms::pss::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::errors::{Error, Result};
use crate::traits::PublicKeyParts;
use crate::traits::SignatureScheme;
use crate::{RsaPrivateKey, RsaPublicKey};
/// Digital signatures using PSS padding.
pub struct Pss {
/// Create blinded signatures.
pub blinded: bool,
/// Digest type to use.
pub digest: Box<dyn DynDigest + Send + Sync>,
/// Salt length.
pub salt_len: usize,
}
impl Pss {
/// New PSS padding for the given digest.
/// Digest output size is used as a salt length.
pub fn new<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
Self::new_with_salt::<T>(<T as Digest>::output_size())
}
/// New PSS padding for the given digest with a salt value of the given length.
pub fn new_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(len: usize) -> Self {
Self {
blinded: false,
digest: Box::new(T::new()),
salt_len: len,
}
}
/// New PSS padding for blinded signatures (RSA-BSSA) for the given digest.
/// Digest output size is used as a salt length.
pub fn new_blinded<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
Self::new_blinded_with_salt::<T>(<T as Digest>::output_size())
}
/// New PSS padding for blinded signatures (RSA-BSSA) for the given digest
/// with a salt value of the given length.
pub fn new_blinded_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(
len: usize,
) -> Self {
Self {
blinded: true,
digest: Box::new(T::new()),
salt_len: len,
}
}
}
impl SignatureScheme for Pss {
fn sign<Rng: CryptoRngCore>(
mut self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
) -> Result<Vec<u8>> {
sign(
rng.ok_or(Error::InvalidPaddingScheme)?,
self.blinded,
priv_key,
hashed,
self.salt_len,
&mut *self.digest,
)
}
fn verify(mut self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()> {
verify(
pub_key,
hashed,
&BigUint::from_bytes_be(sig),
sig.len(),
&mut *self.digest,
self.salt_len,
)
}
}
impl Debug for Pss {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PSS")
.field("blinded", &self.blinded)
.field("digest", &"...")
.field("salt_len", &self.salt_len)
.finish()
}
}
pub(crate) fn verify(
pub_key: &RsaPublicKey,
hashed: &[u8],
sig: &BigUint,
sig_len: usize,
digest: &mut dyn DynDigest,
salt_len: usize,
) -> Result<()> {
if sig_len != pub_key.size() {
return Err(Error::Verification);
}
let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
emsa_pss_verify(hashed, &mut em, salt_len, digest, pub_key.n().bits())
}
pub(crate) fn verify_digest<D>(
pub_key: &RsaPublicKey,
hashed: &[u8],
sig: &BigUint,
sig_len: usize,
salt_len: usize,
) -> Result<()>
where
D: Digest + FixedOutputReset,
{
if sig >= pub_key.n() || sig_len != pub_key.size() {
return Err(Error::Verification);
}
let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
emsa_pss_verify_digest::<D>(hashed, &mut em, salt_len, pub_key.n().bits())
}
/// SignPSS calculates the signature of hashed using RSASSA-PSS.
///
/// Note that hashed must be the result of hashing the input message using the
/// given hash function. The opts argument may be nil, in which case sensible
/// defaults are used.
pub(crate) fn sign<T: CryptoRngCore>(
rng: &mut T,
blind: bool,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt_len: usize,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let mut salt = vec![0; salt_len];
rng.fill_bytes(&mut salt[..]);
sign_pss_with_salt(blind.then_some(rng), priv_key, hashed, &salt, digest)
}
pub(crate) fn sign_digest<T: CryptoRngCore + ?Sized, D: Digest + FixedOutputReset>(
rng: &mut T,
blind: bool,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt_len: usize,
) -> Result<Vec<u8>> {
let mut salt = vec![0; salt_len];
rng.fill_bytes(&mut salt[..]);
sign_pss_with_salt_digest::<_, D>(blind.then_some(rng), priv_key, hashed, &salt)
}
/// signPSSWithSalt calculates the signature of hashed using PSS with specified salt.
///
/// Note that hashed must be the result of hashing the input message using the
/// given hash function. salt is a random sequence of bytes whose length will be
/// later used to verify the signature.
fn sign_pss_with_salt<T: CryptoRngCore>(
blind_rng: Option<&mut T>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt: &[u8],
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let em_bits = priv_key.n().bits() - 1;
let em = emsa_pss_encode(hashed, em_bits, salt, digest)?;
uint_to_zeroizing_be_pad(
rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?,
priv_key.size(),
)
}
fn sign_pss_with_salt_digest<T: CryptoRngCore + ?Sized, D: Digest + FixedOutputReset>(
blind_rng: Option<&mut T>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt: &[u8],
) -> Result<Vec<u8>> {
let em_bits = priv_key.n().bits() - 1;
let em = emsa_pss_encode_digest::<D>(hashed, em_bits, salt)?;
uint_to_zeroizing_be_pad(
rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?,
priv_key.size(),
)
}
/// Returns the [`AlgorithmIdentifierOwned`] associated with PSS signature using a given digest.
pub fn get_default_pss_signature_algo_id<D>() -> pkcs8::spki::Result<AlgorithmIdentifierOwned>
where
D: Digest + AssociatedOid,
{
let salt_len: u8 = <D as Digest>::output_size() as u8;
get_pss_signature_algo_id::<D>(salt_len)
}
fn get_pss_signature_algo_id<D>(salt_len: u8) -> pkcs8::spki::Result<AlgorithmIdentifierOwned>
where
D: Digest + AssociatedOid,
{
const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");
let pss_params = RsaPssParams::new::<D>(salt_len);
Ok(AlgorithmIdentifierOwned {
oid: ID_RSASSA_PSS,
parameters: Some(Any::encode_from(&pss_params)?),
})
}
#[cfg(test)]
mod test {
use crate::pss::{BlindedSigningKey, Pss, Signature, SigningKey, VerifyingKey};
use crate::{RsaPrivateKey, RsaPublicKey};
use hex_literal::hex;
use num_bigint::BigUint;
use num_traits::{FromPrimitive, Num};
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use sha1::{Digest, Sha1};
use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
use signature::{DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner, Verifier};
fn get_private_key() -> RsaPrivateKey {
// In order to generate new test vectors you'll need the PEM form of this key:
// -----BEGIN RSA PRIVATE KEY-----
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
// -----END RSA PRIVATE KEY-----
RsaPrivateKey::from_components(
BigUint::from_str_radix("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077", 10).unwrap(),
BigUint::from_u64(65537).unwrap(),
BigUint::from_str_radix("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861", 10).unwrap(),
vec![
BigUint::from_str_radix("98920366548084643601728869055592650835572950932266967461790948584315647051443",10).unwrap(),
BigUint::from_str_radix("94560208308847015747498523884063394671606671904944666360068158221458669711639", 10).unwrap()
],
).unwrap()
}
#[test]
fn test_verify_pss() {
let priv_key = get_private_key();
let tests = [
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
for (text, sig, expected) in &tests {
let digest = Sha1::digest(text.as_bytes()).to_vec();
let result = pub_key.verify(Pss::new::<Sha1>(), &digest, sig);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pss_signer() {
let priv_key = get_private_key();
let tests = [
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key: VerifyingKey<Sha1> = VerifyingKey::new(pub_key);
for (text, sig, expected) in &tests {
let result = verifying_key.verify(
text.as_bytes(),
&Signature::try_from(sig.as_slice()).unwrap(),
);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pss_digest_signer() {
let priv_key = get_private_key();
let tests = [
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::new(pub_key);
for (text, sig, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let result =
verifying_key.verify_digest(digest, &Signature::try_from(sig.as_slice()).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_sign_and_verify_roundtrip() {
let priv_key = get_private_key();
let tests = ["test\n"];
let rng = ChaCha8Rng::from_seed([42; 32]);
for test in &tests {
let digest = Sha1::digest(test.as_bytes()).to_vec();
let sig = priv_key
.sign_with_rng(&mut rng.clone(), Pss::new::<Sha1>(), &digest)
.expect("failed to sign");
priv_key
.to_public_key()
.verify(Pss::new::<Sha1>(), &digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_blinded_and_verify_roundtrip() {
let priv_key = get_private_key();
let tests = ["test\n"];
let rng = ChaCha8Rng::from_seed([42; 32]);
for test in &tests {
let digest = Sha1::digest(test.as_bytes()).to_vec();
let sig = priv_key
.sign_with_rng(&mut rng.clone(), Pss::new_blinded::<Sha1>(), &digest)
.expect("failed to sign");
priv_key
.to_public_key()
.verify(Pss::new::<Sha1>(), &digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = SigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
verifying_key
.verify(test.as_bytes(), &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_blinded_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
verifying_key
.verify(test.as_bytes(), &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_digest_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = SigningKey::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let mut digest = Sha1::new();
digest.update(test.as_bytes());
let sig = signing_key.sign_digest_with_rng(&mut rng, digest);
let mut digest = Sha1::new();
digest.update(test.as_bytes());
verifying_key
.verify_digest(digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_blinded_digest_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let mut digest = Sha1::new();
digest.update(test.as_bytes());
let sig = signing_key.sign_digest_with_rng(&mut rng, digest);
let mut digest = Sha1::new();
digest.update(test.as_bytes());
verifying_key
.verify_digest(digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_verify_pss_hazmat() {
let priv_key = get_private_key();
let tests = [
(
Sha1::digest("test\n"),
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
Sha1::digest("test\n"),
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
for (text, sig, expected) in &tests {
let result = verifying_key
.verify_prehash(text.as_ref(), &Signature::try_from(sig.as_slice()).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_sign_and_verify_pss_hazmat() {
let priv_key = get_private_key();
let tests = [Sha1::digest("test\n")];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = SigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key
.sign_prehash_with_rng(&mut rng, &test)
.expect("failed to sign");
verifying_key
.verify_prehash(&test, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_pss_blinded_hazmat() {
let priv_key = get_private_key();
let tests = [Sha1::digest("test\n")];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key
.sign_prehash_with_rng(&mut rng, &test)
.expect("failed to sign");
verifying_key
.verify_prehash(&test, &sig)
.expect("failed to verify");
}
}
#[test]
// Tests the corner case where the key is multiple of 8 + 1 bits long
fn test_sign_and_verify_2049bit_key() {
let plaintext = "Hello\n";
let rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = RsaPrivateKey::new(&mut rng.clone(), 2049).unwrap();
let digest = Sha1::digest(plaintext.as_bytes()).to_vec();
let sig = priv_key
.sign_with_rng(&mut rng.clone(), Pss::new::<Sha1>(), &digest)
.expect("failed to sign");
priv_key
.to_public_key()
.verify(Pss::new::<Sha1>(), &digest, &sig)
.expect("failed to verify");
}
}

View File

@@ -0,0 +1,200 @@
use super::{get_pss_signature_algo_id, sign_digest, Signature, VerifyingKey};
use crate::{Result, RsaPrivateKey};
use const_oid::AssociatedOid;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierOwned, AlgorithmIdentifierRef,
AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier,
},
EncodePrivateKey, SecretDocument,
};
use rand_core::CryptoRngCore;
use signature::{
hazmat::RandomizedPrehashSigner, Keypair, RandomizedDigestSigner, RandomizedSigner,
};
use zeroize::ZeroizeOnDrop;
/// Signing key for producing "blinded" RSASSA-PSS signatures as described in
/// [draft-irtf-cfrg-rsa-blind-signatures](https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/).
#[derive(Debug, Clone)]
pub struct BlindedSigningKey<D>
where
D: Digest,
{
inner: RsaPrivateKey,
salt_len: usize,
phantom: PhantomData<D>,
}
impl<D> BlindedSigningKey<D>
where
D: Digest,
{
/// Create a new RSASSA-PSS signing key which produces "blinded"
/// signatures.
/// Digest output size is used as a salt length.
pub fn new(key: RsaPrivateKey) -> Self {
Self::new_with_salt_len(key, <D as Digest>::output_size())
}
/// Create a new RSASSA-PSS signing key which produces "blinded"
/// signatures with a salt of the given length.
pub fn new_with_salt_len(key: RsaPrivateKey, salt_len: usize) -> Self {
Self {
inner: key,
salt_len,
phantom: Default::default(),
}
}
/// Create a new random RSASSA-PSS signing key which produces "blinded"
/// signatures.
/// Digest output size is used as a salt length.
pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
Self::random_with_salt_len(rng, bit_size, <D as Digest>::output_size())
}
/// Create a new random RSASSA-PSS signing key which produces "blinded"
/// signatures with a salt of the given length.
pub fn random_with_salt_len<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
salt_len: usize,
) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
salt_len,
phantom: Default::default(),
})
}
/// Return specified salt length for this key
pub fn salt_len(&self) -> usize {
self.salt_len
}
}
//
// `*Signer` trait impls
//
impl<D> RandomizedSigner<Signature> for BlindedSigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_with_rng(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, true, &self.inner, &D::digest(msg), self.salt_len)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedDigestSigner<D, Signature> for BlindedSigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_digest_with_rng(
&self,
rng: &mut impl CryptoRngCore,
digest: D,
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, true, &self.inner, &digest.finalize(), self.salt_len)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedPrehashSigner<Signature> for BlindedSigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn sign_prehash_with_rng(
&self,
rng: &mut impl CryptoRngCore,
prehash: &[u8],
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, true, &self.inner, prehash, self.salt_len)?
.as_slice()
.try_into()
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPrivateKey> for BlindedSigningKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPrivateKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for BlindedSigningKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
impl<D> DynSignatureAlgorithmIdentifier for BlindedSigningKey<D>
where
D: Digest + AssociatedOid,
{
fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result<AlgorithmIdentifierOwned> {
get_pss_signature_algo_id::<D>(self.salt_len as u8)
}
}
impl<D> EncodePrivateKey for BlindedSigningKey<D>
where
D: Digest,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
self.inner.to_pkcs8_der()
}
}
impl<D> From<RsaPrivateKey> for BlindedSigningKey<D>
where
D: Digest,
{
fn from(key: RsaPrivateKey) -> Self {
Self::new(key)
}
}
impl<D> From<BlindedSigningKey<D>> for RsaPrivateKey
where
D: Digest,
{
fn from(key: BlindedSigningKey<D>) -> Self {
key.inner
}
}
impl<D> Keypair for BlindedSigningKey<D>
where
D: Digest,
{
type VerifyingKey = VerifyingKey<D>;
fn verifying_key(&self) -> Self::VerifyingKey {
VerifyingKey {
inner: self.inner.to_public_key(),
salt_len: self.salt_len,
phantom: Default::default(),
}
}
}
impl<D> ZeroizeOnDrop for BlindedSigningKey<D> where D: Digest {}

74
vendor/rsa/src/pss/signature.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
pub use ::signature::SignatureEncoding;
use spki::{
der::{asn1::BitString, Result as DerResult},
SignatureBitStringEncoding,
};
use crate::algorithms::pad::uint_to_be_pad;
use alloc::{boxed::Box, string::ToString};
use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
use num_bigint::BigUint;
/// RSASSA-PSS signatures as described in [RFC8017 § 8.1].
///
/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
#[derive(Clone, PartialEq, Eq)]
pub struct Signature {
pub(super) inner: BigUint,
pub(super) len: usize,
}
impl SignatureEncoding for Signature {
type Repr = Box<[u8]>;
}
impl SignatureBitStringEncoding for Signature {
fn to_bitstring(&self) -> DerResult<BitString> {
BitString::new(0, self.to_vec())
}
}
impl TryFrom<&[u8]> for Signature {
type Error = signature::Error;
fn try_from(bytes: &[u8]) -> signature::Result<Self> {
Ok(Self {
len: bytes.len(),
inner: BigUint::from_bytes_be(bytes),
})
}
}
impl From<Signature> for Box<[u8]> {
fn from(signature: Signature) -> Box<[u8]> {
uint_to_be_pad(signature.inner, signature.len)
.expect("RSASSA-PKCS1-v1_5 length invariants should've been enforced")
.into_boxed_slice()
}
}
impl Debug for Signature {
fn fmt(&self, fmt: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> {
fmt.debug_tuple("Signature")
.field(&self.to_string())
.finish()
}
}
impl LowerHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:x}", &self.inner)
}
}
impl UpperHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}", &self.inner)
}
}
impl Display for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}", self)
}
}

222
vendor/rsa/src/pss/signing_key.rs vendored Normal file
View File

@@ -0,0 +1,222 @@
use super::{get_pss_signature_algo_id, sign_digest, Signature, VerifyingKey};
use crate::{Result, RsaPrivateKey};
use const_oid::AssociatedOid;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierOwned, AlgorithmIdentifierRef,
AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier,
},
EncodePrivateKey, SecretDocument,
};
use rand_core::CryptoRngCore;
use signature::{
hazmat::RandomizedPrehashSigner, Keypair, RandomizedDigestSigner, RandomizedSigner,
};
use zeroize::ZeroizeOnDrop;
#[cfg(feature = "getrandom")]
use {
rand_core::OsRng,
signature::{hazmat::PrehashSigner, Signer},
};
/// Signing key for producing RSASSA-PSS signatures as described in
/// [RFC8017 § 8.1].
///
/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
#[derive(Debug, Clone)]
pub struct SigningKey<D>
where
D: Digest,
{
inner: RsaPrivateKey,
salt_len: usize,
phantom: PhantomData<D>,
}
impl<D> SigningKey<D>
where
D: Digest,
{
/// Create a new RSASSA-PSS signing key.
/// Digest output size is used as a salt length.
pub fn new(key: RsaPrivateKey) -> Self {
Self::new_with_salt_len(key, <D as Digest>::output_size())
}
/// Create a new RSASSA-PSS signing key with a salt of the given length.
pub fn new_with_salt_len(key: RsaPrivateKey, salt_len: usize) -> Self {
Self {
inner: key,
salt_len,
phantom: Default::default(),
}
}
/// Generate a new random RSASSA-PSS signing key.
/// Digest output size is used as a salt length.
pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
Self::random_with_salt_len(rng, bit_size, <D as Digest>::output_size())
}
/// Generate a new random RSASSA-PSS signing key with a salt of the given length.
pub fn random_with_salt_len<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
salt_len: usize,
) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
salt_len,
phantom: Default::default(),
})
}
/// Return specified salt length for this key
pub fn salt_len(&self) -> usize {
self.salt_len
}
}
//
// `*Signer` trait impls
//
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_digest_with_rng(
&self,
rng: &mut impl CryptoRngCore,
digest: D,
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, false, &self.inner, &digest.finalize(), self.salt_len)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedSigner<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_with_rng(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> signature::Result<Signature> {
self.try_sign_digest_with_rng(rng, D::new_with_prefix(msg))
}
}
impl<D> RandomizedPrehashSigner<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn sign_prehash_with_rng(
&self,
rng: &mut impl CryptoRngCore,
prehash: &[u8],
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, false, &self.inner, prehash, self.salt_len)?
.as_slice()
.try_into()
}
}
#[cfg(feature = "getrandom")]
impl<D> PrehashSigner<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
self.sign_prehash_with_rng(&mut OsRng, prehash)
}
}
#[cfg(feature = "getrandom")]
impl<D> Signer<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
self.try_sign_with_rng(&mut OsRng, msg)
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPrivateKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
impl<D> DynSignatureAlgorithmIdentifier for SigningKey<D>
where
D: Digest + AssociatedOid,
{
fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result<AlgorithmIdentifierOwned> {
get_pss_signature_algo_id::<D>(self.salt_len as u8)
}
}
impl<D> EncodePrivateKey for SigningKey<D>
where
D: Digest,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
self.inner.to_pkcs8_der()
}
}
impl<D> From<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn from(key: RsaPrivateKey) -> Self {
Self::new(key)
}
}
impl<D> From<SigningKey<D>> for RsaPrivateKey
where
D: Digest,
{
fn from(key: SigningKey<D>) -> Self {
key.inner
}
}
impl<D> Keypair for SigningKey<D>
where
D: Digest,
{
type VerifyingKey = VerifyingKey<D>;
fn verifying_key(&self) -> Self::VerifyingKey {
VerifyingKey {
inner: self.inner.to_public_key(),
salt_len: self.salt_len,
phantom: Default::default(),
}
}
}
impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}

158
vendor/rsa/src/pss/verifying_key.rs vendored Normal file
View File

@@ -0,0 +1,158 @@
use super::{verify_digest, Signature};
use crate::RsaPublicKey;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier},
Document, EncodePublicKey,
};
use signature::{hazmat::PrehashVerifier, DigestVerifier, Verifier};
/// Verifying key for checking the validity of RSASSA-PSS signatures as
/// described in [RFC8017 § 8.1].
///
/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
#[derive(Debug)]
pub struct VerifyingKey<D>
where
D: Digest,
{
pub(super) inner: RsaPublicKey,
pub(super) salt_len: usize,
pub(super) phantom: PhantomData<D>,
}
impl<D> VerifyingKey<D>
where
D: Digest,
{
/// Create a new RSASSA-PSS verifying key.
/// Digest output size is used as a salt length.
pub fn new(key: RsaPublicKey) -> Self {
Self::new_with_salt_len(key, <D as Digest>::output_size())
}
/// Create a new RSASSA-PSS verifying key.
pub fn new_with_salt_len(key: RsaPublicKey, salt_len: usize) -> Self {
Self {
inner: key,
salt_len,
phantom: Default::default(),
}
}
}
//
// `*Verifier` trait impls
//
impl<D> DigestVerifier<D, Signature> for VerifyingKey<D>
where
D: Digest + FixedOutputReset,
{
fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> {
verify_digest::<D>(
&self.inner,
&digest.finalize(),
&signature.inner,
signature.len,
self.salt_len,
)
.map_err(|e| e.into())
}
}
impl<D> PrehashVerifier<Signature> for VerifyingKey<D>
where
D: Digest + FixedOutputReset,
{
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> {
verify_digest::<D>(
&self.inner,
prehash,
&signature.inner,
signature.len,
self.salt_len,
)
.map_err(|e| e.into())
}
}
impl<D> Verifier<Signature> for VerifyingKey<D>
where
D: Digest + FixedOutputReset,
{
fn verify(&self, msg: &[u8], signature: &Signature) -> signature::Result<()> {
verify_digest::<D>(
&self.inner,
&D::digest(msg),
&signature.inner,
signature.len,
self.salt_len,
)
.map_err(|e| e.into())
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPublicKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for VerifyingKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
// Implemented manually so we don't have to bind D with Clone
impl<D> Clone for VerifyingKey<D>
where
D: Digest,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
salt_len: self.salt_len,
phantom: Default::default(),
}
}
}
impl<D> EncodePublicKey for VerifyingKey<D>
where
D: Digest,
{
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
self.inner.to_public_key_der()
}
}
impl<D> From<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn from(key: RsaPublicKey) -> Self {
Self::new(key)
}
}
impl<D> From<VerifyingKey<D>> for RsaPublicKey
where
D: Digest,
{
fn from(key: VerifyingKey<D>) -> Self {
key.inner
}
}

9
vendor/rsa/src/traits.rs vendored Normal file
View File

@@ -0,0 +1,9 @@
//! RSA-related trait definitions.
mod encryption;
pub(crate) mod keys;
mod padding;
pub use encryption::{Decryptor, EncryptingKeypair, RandomizedDecryptor, RandomizedEncryptor};
pub use keys::{PrivateKeyParts, PublicKeyParts};
pub use padding::{PaddingScheme, SignatureScheme};

42
vendor/rsa/src/traits/encryption.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
//! Encryption-related traits.
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
use crate::errors::Result;
/// Encrypt the message using provided random source
pub trait RandomizedEncryptor {
/// Encrypt the given message.
fn encrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>>;
}
/// Decrypt the given message
pub trait Decryptor {
/// Decrypt the given message.
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>>;
}
/// Decrypt the given message using provided random source
pub trait RandomizedDecryptor {
/// Decrypt the given message.
fn decrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>>;
}
/// Encryption keypair with an associated encryption key.
pub trait EncryptingKeypair {
/// Encrypting key type for this keypair.
type EncryptingKey: Clone;
/// Get the encrypting key which can encrypt messages to be decrypted by
/// the decryption key portion of this keypair.
fn encrypting_key(&self) -> Self::EncryptingKey;
}

65
vendor/rsa/src/traits/keys.rs vendored Normal file
View File

@@ -0,0 +1,65 @@
//! Traits related to the key components
use num_bigint::{BigInt, BigUint};
use zeroize::Zeroize;
/// Components of an RSA public key.
pub trait PublicKeyParts {
/// Returns the modulus of the key.
fn n(&self) -> &BigUint;
/// Returns the public exponent of the key.
fn e(&self) -> &BigUint;
/// Returns the modulus size in bytes. Raw signatures and ciphertexts for
/// or by this public key will have the same size.
fn size(&self) -> usize {
(self.n().bits() + 7) / 8
}
}
/// Components of an RSA private key.
pub trait PrivateKeyParts: PublicKeyParts {
/// Returns the private exponent of the key.
fn d(&self) -> &BigUint;
/// Returns the prime factors.
fn primes(&self) -> &[BigUint];
/// Returns the precomputed dp value, D mod (P-1)
fn dp(&self) -> Option<&BigUint>;
/// Returns the precomputed dq value, D mod (Q-1)
fn dq(&self) -> Option<&BigUint>;
/// Returns the precomputed qinv value, Q^-1 mod P
fn qinv(&self) -> Option<&BigInt>;
/// Returns an iterator over the CRT Values
fn crt_values(&self) -> Option<&[CrtValue]>;
}
/// Contains the precomputed Chinese remainder theorem values.
#[derive(Debug, Clone)]
pub struct CrtValue {
/// D mod (prime - 1)
pub(crate) exp: BigInt,
/// R·Coeff ≡ 1 mod Prime.
pub(crate) coeff: BigInt,
/// product of primes prior to this (inc p and q)
pub(crate) r: BigInt,
}
impl Zeroize for CrtValue {
fn zeroize(&mut self) {
self.exp.zeroize();
self.coeff.zeroize();
self.r.zeroize();
}
}
impl Drop for CrtValue {
fn drop(&mut self) {
self.zeroize();
}
}

49
vendor/rsa/src/traits/padding.rs vendored Normal file
View File

@@ -0,0 +1,49 @@
//! Supported padding schemes.
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
use crate::errors::Result;
use crate::key::{RsaPrivateKey, RsaPublicKey};
/// Padding scheme used for encryption.
pub trait PaddingScheme {
/// Decrypt the given message using the given private key.
///
/// If an `rng` is passed, it uses RSA blinding to help mitigate timing
/// side-channel attacks.
fn decrypt<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>>;
/// Encrypt the given message using the given public key.
fn encrypt<Rng: CryptoRngCore>(
self,
rng: &mut Rng,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>>;
}
/// Digital signature scheme.
pub trait SignatureScheme {
/// Sign the given digest.
fn sign<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
) -> Result<Vec<u8>>;
/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
fn verify(self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()>;
}