Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pkcs5.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
toolchain: ${{ matrix.rust }}
targets: ${{ matrix.target }}
- uses: RustCrypto/actions/cargo-hack-install@master
- run: cargo hack build --target ${{ matrix.target }} --feature-powerset --exclude-features std
- run: cargo hack build --target ${{ matrix.target }} --feature-powerset --exclude-features getrandom,std

# TODO(tarcieri): re-enable this when we're not using unpublished prerelease dependencies
# minimal-versions:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pkcs5/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ cbc = { version = "0.1.2", optional = true }
aes = { version = "0.8.3", optional = true, default-features = false }
des = { version = "0.8.1", optional = true, default-features = false }
pbkdf2 = { version = "0.12.1", optional = true, default-features = false }
rand_core = { version = "0.6.4", optional = true, default-features = false }
scrypt = { version = "0.11", optional = true, default-features = false }
sha1 = { version = "0.10.6", optional = true, default-features = false }
sha2 = { version = "0.10.8", optional = true, default-features = false }
Expand All @@ -34,6 +35,7 @@ hex-literal = "0.4"
alloc = []
3des = ["dep:des", "pbes2"]
des-insecure = ["dep:des", "pbes2"]
getrandom = ["rand_core/getrandom"]
pbes2 = ["dep:aes", "dep:cbc", "dep:pbkdf2", "dep:scrypt", "dep:sha2"]
sha1-insecure = ["dep:sha1", "pbes2"]

Expand Down
3 changes: 3 additions & 0 deletions pkcs5/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
//! the [`Decode`] and [`Encode`] traits from the [`der`] crate, and can be
//! used for decoding/encoding PKCS#5 `AlgorithmIdentifier` fields.
//!
//! The [`pbes2::Parameters`] struct can be used to generate new encryption
//! parameters when encrypting new keys.
//!
//! [RFC 8018]: https://tools.ietf.org/html/rfc8018

#[cfg(all(feature = "alloc", feature = "pbes2"))]
Expand Down
69 changes: 69 additions & 0 deletions pkcs5/src/pbes2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ use der::{
Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Writer,
};

#[cfg(feature = "rand_core")]
use rand_core::CryptoRngCore;

#[cfg(all(feature = "alloc", feature = "pbes2"))]
use alloc::vec::Vec;

Expand Down Expand Up @@ -75,6 +78,42 @@ pub struct Parameters {
}

impl Parameters {
/// Default length of an initialization vector.
#[cfg(feature = "rand_core")]
const DEFAULT_IV_LEN: usize = AES_BLOCK_SIZE;

/// Default length of a salt for password hashing.
#[cfg(feature = "rand_core")]
const DEFAULT_SALT_LEN: usize = 16;

/// Generate PBES2 parameters using the recommended algorithm settings and
/// a randomly generated salt and IV.
///
/// This is currently an alias for [`Parameters::scrypt`]. See that method
/// for more information.
#[cfg(all(feature = "pbes2", feature = "rand_core"))]
pub fn recommended(rng: &mut impl CryptoRngCore) -> Self {
Self::scrypt(rng)
}

/// Generate PBES2 parameters using PBKDF2 as the password hashing
/// algorithm, using that algorithm's recommended algorithm settings
/// (OWASP recommended default: 600,000 rounds) along with a randomly
/// generated salt and IV.
///
/// This will use AES-256-CBC as the encryption algorithm and SHA-256 as
/// the hash function for PBKDF2.
#[cfg(feature = "rand_core")]
pub fn pbkdf2(rng: &mut impl CryptoRngCore) -> Self {
let mut iv = [0u8; Self::DEFAULT_IV_LEN];
rng.fill_bytes(&mut iv);

let mut salt = [0u8; Self::DEFAULT_SALT_LEN];
rng.fill_bytes(&mut salt);

Self::pbkdf2_sha256_aes256cbc(600_000, &salt, iv).expect("invalid PBKDF2 parameters")
}

/// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based
/// key derivation function and AES-128-CBC as the symmetric cipher.
pub fn pbkdf2_sha256_aes128cbc(
Expand All @@ -99,6 +138,36 @@ impl Parameters {
Ok(Self { kdf, encryption })
}

/// Generate PBES2 parameters using scrypt as the password hashing
/// algorithm, using that algorithm's recommended algorithm settings
/// along with a randomly generated salt and IV.
///
/// This will use AES-256-CBC as the encryption algorithm.
///
/// scrypt parameters are deliberately chosen to retain compatibility with
/// OpenSSL v3. See [RustCrypto/formats#1205] for more information.
/// Parameter choices are as follows:
///
/// - `log_n`: 14
/// - `r`: 8
/// - `p`: 1
/// - salt length: 16
///
/// [RustCrypto/formats#1205]: https://github.com/RustCrypto/formats/issues/1205
#[cfg(all(feature = "pbes2", feature = "rand_core"))]
pub fn scrypt(rng: &mut impl CryptoRngCore) -> Self {
let mut iv = [0u8; Self::DEFAULT_IV_LEN];
rng.fill_bytes(&mut iv);

let mut salt = [0u8; Self::DEFAULT_SALT_LEN];
rng.fill_bytes(&mut salt);

scrypt::Params::new(14, 8, 1, 32)
.ok()
.and_then(|params| Self::scrypt_aes256cbc(params, &salt, iv).ok())
.expect("invalid scrypt parameters")
}

/// Initialize PBES2 parameters using scrypt as the password-based
/// key derivation function and AES-128-CBC as the symmetric cipher.
///
Expand Down