Add missing rustdoc comments; enable missing_docs
lint (#216)
Several types and methods were missing documentation. This commit adds document and enables warnings for `missing_docs`. Additionally it updates all references to PKCS#1 RFCs to use RFC8017, which documents the latest version of PKCS#1.
This commit is contained in:
parent
a857c8f785
commit
eeb18ee88d
@ -1,4 +1,5 @@
|
||||
use alloc::vec;
|
||||
//! Useful algorithms related to RSA.
|
||||
|
||||
use digest::{Digest, DynDigest, FixedOutputReset};
|
||||
use num_bigint::traits::ModInverse;
|
||||
use num_bigint::{BigUint, RandPrime};
|
||||
|
@ -1,26 +1,64 @@
|
||||
//! 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,
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ use crate::padding::PaddingScheme;
|
||||
use crate::raw::{DecryptionPrimitive, EncryptionPrimitive};
|
||||
use crate::{oaep, pkcs1v15, pss};
|
||||
|
||||
/// Components of an RSA public key.
|
||||
pub trait PublicKeyParts {
|
||||
/// Returns the modulus of the key.
|
||||
fn n(&self) -> &BigUint;
|
||||
|
32
src/lib.rs
32
src/lib.rs
@ -1,9 +1,17 @@
|
||||
//! RSA Implementation in pure Rust.
|
||||
//!
|
||||
//! It supports several schemes described in [RFC8017]:
|
||||
//!
|
||||
//! - OAEP encryption scheme
|
||||
//! - PKCS#1 v1.5 encryption scheme
|
||||
//! - PKCS#1 v1.5 signature scheme
|
||||
//! - PSS signature scheme
|
||||
//!
|
||||
//! These schemes are described below.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! Using PKCS1v15.
|
||||
//! Using PKCS#1 v1.5.
|
||||
//! ```
|
||||
//! use rsa::{PublicKey, RsaPrivateKey, RsaPublicKey, PaddingScheme};
|
||||
//!
|
||||
@ -47,7 +55,7 @@
|
||||
//! assert_eq!(&data[..], &dec_data[..]);
|
||||
//! ```
|
||||
//!
|
||||
//! Using PKCS1v15 signatures
|
||||
//! Using PKCS#1 v1.5 signatures
|
||||
//! ```
|
||||
//! use rsa::RsaPrivateKey;
|
||||
//! use rsa::pkcs1v15::{SigningKey, VerifyingKey};
|
||||
@ -95,8 +103,8 @@
|
||||
//!
|
||||
//! ## PKCS#1 RSA Key Encoding
|
||||
//!
|
||||
//! PKCS#1 is a legacy format for encoding RSA keys as binary (DER) or text
|
||||
//! (PEM) data.
|
||||
//! 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.:
|
||||
@ -112,8 +120,8 @@
|
||||
//! toplevel of the `rsa` crate:
|
||||
//!
|
||||
//! - [`pkcs1::DecodeRsaPrivateKey`]: decode RSA private keys from PKCS#1
|
||||
//! - [`pkcs1::DecodeRsaPublicKey`]: decode RSA public 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
|
||||
@ -156,8 +164,8 @@
|
||||
//! toplevel of the `rsa` crate:
|
||||
//!
|
||||
//! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8
|
||||
//! - [`pkcs8::DecodePublicKey`]: decode public 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
|
||||
@ -183,10 +191,17 @@
|
||||
//! # 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_attr(not(test), no_std)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
@ -196,15 +211,10 @@ extern crate std;
|
||||
pub use num_bigint::BigUint;
|
||||
pub use rand_core;
|
||||
|
||||
/// Useful algorithms.
|
||||
pub mod algorithms;
|
||||
/// Error types.
|
||||
pub mod errors;
|
||||
/// Supported padding schemes.
|
||||
pub mod padding;
|
||||
/// RSASSA-PKCS1-v1_5 Signature support
|
||||
pub mod pkcs1v15;
|
||||
/// RSASSA-PSS Signature support
|
||||
pub mod pss;
|
||||
|
||||
mod dummy_rng;
|
||||
|
20
src/oaep.rs
20
src/oaep.rs
@ -15,9 +15,13 @@ use crate::key::{self, PrivateKey, PublicKey};
|
||||
// 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;
|
||||
|
||||
/// Encrypts the given message with RSA and the padding
|
||||
/// scheme from [PKCS#1 OAEP](https://datatracker.ietf.org/doc/html/rfc3447#section-7.1.1). The message must be no longer than the
|
||||
/// length of the public modulus minus (2+ 2*hash.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
|
||||
#[inline]
|
||||
pub fn encrypt<R: RngCore + CryptoRng, K: PublicKey>(
|
||||
rng: &mut R,
|
||||
@ -63,14 +67,18 @@ pub fn encrypt<R: RngCore + CryptoRng, K: PublicKey>(
|
||||
pub_key.raw_encryption_primitive(&em, pub_key.size())
|
||||
}
|
||||
|
||||
/// Decrypts a plaintext using RSA and the padding scheme from [pkcs1# OAEP](https://datatracker.ietf.org/doc/html/rfc3447#section-7.1.2)
|
||||
/// 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.
|
||||
/// 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 fn decrypt<R: RngCore + CryptoRng, SK: PrivateKey>(
|
||||
rng: Option<&mut R>,
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Supported padding schemes.
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::{String, ToString};
|
||||
use core::fmt;
|
||||
@ -11,29 +13,44 @@ use crate::pkcs1v15;
|
||||
pub enum PaddingScheme {
|
||||
/// Encryption and Decryption using PKCS1v15 padding.
|
||||
PKCS1v15Encrypt,
|
||||
|
||||
/// Sign and Verify using PKCS1v15 padding.
|
||||
PKCS1v15Sign {
|
||||
/// Length of hash to use.
|
||||
hash_len: Option<usize>,
|
||||
|
||||
/// Prefix.
|
||||
prefix: Box<[u8]>,
|
||||
},
|
||||
/// Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc3447#section-7.1.1).
|
||||
|
||||
/// 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/rfc2437#section-10.2.1).
|
||||
/// 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`.
|
||||
OAEP {
|
||||
/// Digest type to use.
|
||||
digest: Box<dyn DynDigest + Send + Sync>,
|
||||
|
||||
/// Digest to use for Mask Generation Function (MGF).
|
||||
mgf_digest: Box<dyn DynDigest + Send + Sync>,
|
||||
|
||||
/// Optional label.
|
||||
label: Option<String>,
|
||||
},
|
||||
|
||||
/// Sign and Verify using PSS padding.
|
||||
PSS {
|
||||
/// Digest type to use.
|
||||
digest: Box<dyn DynDigest + Send + Sync>,
|
||||
|
||||
/// Salt length.
|
||||
salt_len: Option<usize>,
|
||||
},
|
||||
}
|
||||
@ -58,10 +75,14 @@ impl fmt::Debug for PaddingScheme {
|
||||
}
|
||||
|
||||
impl PaddingScheme {
|
||||
/// Create new PKCS#1 v1.5 encryption padding.
|
||||
pub fn new_pkcs1v15_encrypt() -> Self {
|
||||
PaddingScheme::PKCS1v15Encrypt
|
||||
}
|
||||
|
||||
/// Create new PKCS#1 v1.5 padding for computing a raw signature.
|
||||
///
|
||||
/// This sets `hash_len` to `None` and uses an empty `prefix`.
|
||||
pub fn new_pkcs1v15_sign_raw() -> Self {
|
||||
PaddingScheme::PKCS1v15Sign {
|
||||
hash_len: None,
|
||||
@ -69,6 +90,10 @@ impl PaddingScheme {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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_pkcs1v15_sign<D>() -> Self
|
||||
where
|
||||
D: Digest + AssociatedOid,
|
||||
@ -159,6 +184,7 @@ impl PaddingScheme {
|
||||
}
|
||||
}
|
||||
|
||||
/// New PSS padding for the given digest.
|
||||
pub fn new_pss<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
|
||||
PaddingScheme::PSS {
|
||||
digest: Box::new(T::new()),
|
||||
@ -166,6 +192,7 @@ impl PaddingScheme {
|
||||
}
|
||||
}
|
||||
|
||||
/// New PSS padding for the given digest with a salt value of the given length.
|
||||
pub fn new_pss_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(len: usize) -> Self {
|
||||
PaddingScheme::PSS {
|
||||
digest: Box::new(T::new()),
|
||||
|
@ -1,4 +1,7 @@
|
||||
use alloc::vec;
|
||||
//! PKCS#1 v1.5 support as described in [RFC8017 § 8.2].
|
||||
//!
|
||||
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
|
||||
use core::marker::PhantomData;
|
||||
@ -20,6 +23,9 @@ use crate::errors::{Error, Result};
|
||||
use crate::key::{self, PrivateKey, PublicKey};
|
||||
use crate::{RsaPrivateKey, RsaPublicKey};
|
||||
|
||||
/// PKCS#1 v1.5 signatures as described in [RFC8017 § 8.2].
|
||||
///
|
||||
/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
|
||||
#[derive(Clone)]
|
||||
pub struct Signature {
|
||||
bytes: Vec<u8>,
|
||||
@ -95,9 +101,9 @@ impl Display for Signature {
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
/// 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]
|
||||
pub(crate) fn encrypt<R: RngCore + CryptoRng, PK: PublicKey>(
|
||||
rng: &mut R,
|
||||
@ -122,13 +128,14 @@ pub(crate) fn encrypt<R: RngCore + CryptoRng, PK: PublicKey>(
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// 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]
|
||||
pub(crate) fn decrypt<R: RngCore + CryptoRng, SK: PrivateKey>(
|
||||
rng: Option<&mut R>,
|
||||
@ -145,19 +152,19 @@ pub(crate) fn decrypt<R: RngCore + CryptoRng, SK: PrivateKey>(
|
||||
Ok(out[index as usize..].to_vec())
|
||||
}
|
||||
|
||||
// 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.
|
||||
/// 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]
|
||||
pub(crate) fn sign<R: RngCore + CryptoRng, SK: PrivateKey>(
|
||||
rng: Option<&mut R>,
|
||||
@ -218,7 +225,7 @@ pub(crate) fn verify<PK: PublicKey>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// prefix = 0x30 <oid_len + 8 + digest_len> 0x30 <oid_len + 4> 0x06 <oid_len> oid 0x05 0x00 0x04 <digest_len>
|
||||
/// prefix = 0x30 <oid_len + 8 + digest_len> 0x30 <oid_len + 4> 0x06 <oid_len> oid 0x05 0x00 0x04 <digest_len>
|
||||
#[inline]
|
||||
pub(crate) fn generate_prefix<D>() -> Vec<u8>
|
||||
where
|
||||
@ -305,6 +312,9 @@ fn non_zero_random_bytes<R: RngCore + CryptoRng>(rng: &mut R, data: &mut [u8]) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Signing key for PKCS#1 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
|
||||
@ -319,14 +329,7 @@ impl<D> SigningKey<D>
|
||||
where
|
||||
D: Digest,
|
||||
{
|
||||
pub(crate) fn key(&self) -> &RsaPrivateKey {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub(crate) fn prefix(&self) -> Vec<u8> {
|
||||
self.prefix.clone()
|
||||
}
|
||||
|
||||
/// Create a new signing key from the give RSA private key.
|
||||
pub fn new(key: RsaPrivateKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
@ -334,6 +337,14 @@ where
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn key(&self) -> &RsaPrivateKey {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub(crate) fn prefix(&self) -> Vec<u8> {
|
||||
self.prefix.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> From<RsaPrivateKey> for SigningKey<D>
|
||||
@ -358,6 +369,7 @@ impl<D> SigningKey<D>
|
||||
where
|
||||
D: Digest + AssociatedOid,
|
||||
{
|
||||
/// Create a new verifying key with a prefix for the digest `D`.
|
||||
pub fn new_with_prefix(key: RsaPrivateKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
@ -454,6 +466,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifying key for PKCS#1 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 VerifyingKey<D>
|
||||
where
|
||||
@ -468,6 +483,7 @@ impl<D> VerifyingKey<D>
|
||||
where
|
||||
D: Digest,
|
||||
{
|
||||
/// Create a new verifying key from an RSA public key.
|
||||
pub fn new(key: RsaPublicKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
@ -499,6 +515,7 @@ impl<D> VerifyingKey<D>
|
||||
where
|
||||
D: Digest + AssociatedOid,
|
||||
{
|
||||
/// Create a new verifying key with a prefix for the digest `D`.
|
||||
pub fn new_with_prefix(key: RsaPublicKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
|
57
src/pss.rs
57
src/pss.rs
@ -1,4 +1,10 @@
|
||||
use alloc::vec;
|
||||
//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
|
||||
//!
|
||||
//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
|
||||
//!
|
||||
//! [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 core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
|
||||
@ -19,6 +25,9 @@ use crate::errors::{Error, Result};
|
||||
use crate::key::{PrivateKey, PublicKey};
|
||||
use crate::{RsaPrivateKey, RsaPublicKey};
|
||||
|
||||
/// RSASSA-PSS signatures as described in [RFC8017 § 8.1].
|
||||
///
|
||||
/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
|
||||
#[derive(Clone)]
|
||||
pub struct Signature {
|
||||
bytes: Vec<u8>,
|
||||
@ -128,6 +137,7 @@ where
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@ -172,6 +182,7 @@ fn generate_salt<T: RngCore + ?Sized, SK: PrivateKey>(
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@ -521,6 +532,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -535,10 +550,7 @@ impl<D> SigningKey<D>
|
||||
where
|
||||
D: Digest,
|
||||
{
|
||||
pub(crate) fn key(&self) -> &RsaPrivateKey {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Create a new RSASSA-PSS signing key.
|
||||
pub fn new(key: RsaPrivateKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
@ -547,6 +559,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
@ -554,6 +567,10 @@ where
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn key(&self) -> &RsaPrivateKey {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> From<RsaPrivateKey> for SigningKey<D>
|
||||
@ -644,6 +661,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -658,10 +677,8 @@ impl<D> BlindedSigningKey<D>
|
||||
where
|
||||
D: Digest,
|
||||
{
|
||||
pub(crate) fn key(&self) -> &RsaPrivateKey {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Create a new RSASSA-PSS signing key which produces "blinded"
|
||||
/// signatures.
|
||||
pub fn new(key: RsaPrivateKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
@ -670,6 +687,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
@ -677,6 +696,10 @@ where
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn key(&self) -> &RsaPrivateKey {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> From<RsaPrivateKey> for BlindedSigningKey<D>
|
||||
@ -767,6 +790,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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, Clone)]
|
||||
pub struct VerifyingKey<D>
|
||||
where
|
||||
@ -780,6 +807,7 @@ impl<D> VerifyingKey<D>
|
||||
where
|
||||
D: Digest,
|
||||
{
|
||||
/// Create a new RSASSA-PSS verifying key.
|
||||
pub fn new(key: RsaPublicKey) -> Self {
|
||||
Self {
|
||||
inner: key,
|
||||
@ -1195,7 +1223,8 @@ mod test {
|
||||
let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
|
||||
|
||||
for (text, sig, expected) in &tests {
|
||||
let result = verifying_key.verify_prehash(text.as_ref(), &Signature::from_bytes(sig).unwrap());
|
||||
let result =
|
||||
verifying_key.verify_prehash(text.as_ref(), &Signature::from_bytes(sig).unwrap());
|
||||
match expected {
|
||||
true => result.expect("failed to verify"),
|
||||
false => {
|
||||
@ -1216,7 +1245,9 @@ mod test {
|
||||
let verifying_key = VerifyingKey::from(&signing_key);
|
||||
|
||||
for test in &tests {
|
||||
let sig = signing_key.sign_prehash_with_rng(&mut rng, &test).expect("failed to sign");
|
||||
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");
|
||||
@ -1234,7 +1265,9 @@ mod test {
|
||||
let verifying_key = VerifyingKey::from(&signing_key);
|
||||
|
||||
for test in &tests {
|
||||
let sig = signing_key.sign_prehash_with_rng(&mut rng, &test).expect("failed to sign");
|
||||
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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user