Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing rustdoc comments; enable missing_docs lint #216

Merged
merged 1 commit into from Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/algorithms.rs
@@ -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};
Expand Down
38 changes: 38 additions & 0 deletions src/errors.rs
@@ -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.
tarcieri marked this conversation as resolved.
Show resolved Hide resolved
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,
}

Expand Down
1 change: 1 addition & 0 deletions src/key.rs
Expand Up @@ -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;
Expand Down
32 changes: 21 additions & 11 deletions 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};
//!
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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.:
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Comment on lines +198 to +199
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason rustdoc is failing to link these. Not sure why, but this at least works around the bug.

See: https://docs.rs/rsa/latest/rsa/#pkcs8-rsa-key-encoding

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange. This works for me with the local cargo doc.


#![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;
Expand All @@ -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;
Expand Down
20 changes: 14 additions & 6 deletions src/oaep.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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>,
Expand Down
33 changes: 30 additions & 3 deletions src/padding.rs
@@ -1,3 +1,5 @@
//! Supported padding schemes.

use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt;
Expand All @@ -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>,
},
}
Expand All @@ -58,17 +75,25 @@ 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,
prefix: Box::new([]),
}
}

/// 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,
Expand Down Expand Up @@ -159,13 +184,15 @@ 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()),
salt_len: None,
}
}

/// 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()),
Expand Down