Crate rsa

source ·
Expand description

RustCrypto: RSA

crates.io Documentation Build Status dependency status MSRV Project Chat

A portable RSA implementation in pure Rust.

Example

use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};

let mut rng = rand::thread_rng();
let bits = 2048;
let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
let pub_key = RsaPublicKey::from(&priv_key);

// Encrypt
let data = b"hello world";
let enc_data = pub_key.encrypt(&mut rng, Pkcs1v15Encrypt, &data[..]).expect("failed to encrypt");
assert_ne!(&data[..], &enc_data[..]);

// Decrypt
let dec_data = priv_key.decrypt(Pkcs1v15Encrypt, &enc_data).expect("failed to decrypt");
assert_eq!(&data[..], &dec_data[..]);

Note: If you encounter unusually slow key generation time while using RsaPrivateKey::new you can try to compile in release mode or add the following to your Cargo.toml. Key generation is much faster when building with higher optimization levels, but this will increase the compile time a bit.

[profile.debug]
opt-level = 3

If you don’t want to turn on optimizations for all dependencies, you can only optimize the num-bigint-dig dependency. This should give most of the speedups.

[profile.dev.package.num-bigint-dig]
opt-level = 3

Status

Currently at Phase 1 (v) 🚧

There will be three phases before 1.0 🚢 can be released.

  1. 🚧 Make it work
    • Prime generation ✅
    • Key generation ✅
    • PKCS1v1.5: Encryption & Decryption ✅
    • PKCS1v1.5: Sign & Verify ✅
    • PKCS1v1.5 (session key): Encryption & Decryption
    • OAEP: Encryption & Decryption
    • PSS: Sign & Verify
    • Key import & export
  2. 🚀 Make it fast
    • Benchmarks ✅
    • compare to other implementations 🚧
    • optimize 🚧
  3. 🔐 Make it secure
    • Fuzz testing
    • Security Audits

⚠️Security Warning

This crate has received one security audit by Include Security, with only one minor finding which has since been addressed.

See the open security issues on our issue tracker for other known problems.

Notably the implementation of modular exponentiation is not constant time, but timing variability is masked using random blinding, a commonly used technique. This crate is vulnerable to the Marvin Attack which could enable private key recovery by a network attacker (see RUSTSEC-2023-0071).

You can follow our work on mitigating this issue in #390.

Minimum Supported Rust Version (MSRV)

All crates in this repository support Rust 1.65 or higher.

In the future MSRV can be changed, but it will be done with a minor version bump.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Supported algorithms

This crate supports several schemes described in RFC8017:

These schemes are described below.

Usage

OAEP encryption

Note: requires sha2 feature of rsa crate is enabled.

use rsa::{RsaPrivateKey, RsaPublicKey, Oaep, sha2::Sha256};

let mut rng = rand::thread_rng();

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();

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.

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();

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.

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();

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.:

-----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:

Example

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)?;

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.:

-----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:

Example

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)?;

Re-exports

Modules

Structs

  • A big unsigned integer type.
  • Contains the precomputed Chinese remainder theorem values.
  • Represents a whole RSA key, public and private parts.
  • Represents the public part of an RSA key.