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

4 changes: 3 additions & 1 deletion pkcs8/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ spki = "0.8"

# optional dependencies
ctutils = { version = "0.4", optional = true }
getrandom = { version = "0.4", optional = true, features = ["sys_rng"] }
pkcs5 = { version = "0.8", optional = true, features = ["rand_core"] }
rand_core = { version = "0.10", optional = true, default-features = false }

Expand All @@ -35,7 +36,8 @@ std = ["alloc", "der/std", "spki/std"]

3des = ["encryption", "pkcs5/3des"]
des-insecure = ["encryption", "pkcs5/des-insecure"]
encryption = ["alloc", "pkcs5/alloc", "pkcs5/pbes2", "rand_core"]
encryption = ["alloc", "pkcs5/alloc", "pkcs5/pbes2", "dep:rand_core"]
getrandom = ["encryption", "pkcs5/getrandom", "dep:getrandom"]
pem = ["alloc", "der/pem", "spki/pem"]
sha1-insecure = ["encryption", "pkcs5/sha1-insecure"]

Expand Down
13 changes: 10 additions & 3 deletions pkcs8/src/encrypted_private_key_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,29 @@ where
.try_into()?)
}

/// Encrypt the given ASN.1 DER document using a symmetric encryption key
/// derived from the provided password.
#[cfg(feature = "getrandom")]
pub(crate) fn encrypt(password: impl AsRef<[u8]>, doc: &[u8]) -> Result<SecretDocument> {
Self::encrypt_with_rng(&mut getrandom::SysRng, password, doc)
}

/// Encrypt the given ASN.1 DER document using a symmetric encryption key
/// derived from the provided password.
#[cfg(feature = "encryption")]
pub(crate) fn encrypt<R: TryCryptoRng>(
pub(crate) fn encrypt_with_rng<R: TryCryptoRng>(
rng: &mut R,
password: impl AsRef<[u8]>,
doc: &[u8],
) -> Result<SecretDocument> {
let pbes2_params = pbes2::Parameters::generate_recommended(rng)?;
EncryptedPrivateKeyInfoOwned::encrypt_with(pbes2_params, password, doc)
EncryptedPrivateKeyInfoOwned::encrypt_with_params(pbes2_params, password, doc)
}

/// Encrypt this private key using a symmetric encryption key derived
/// from the provided password and [`pbes2::Parameters`].
#[cfg(feature = "encryption")]
pub(crate) fn encrypt_with(
pub(crate) fn encrypt_with_params(
pbes2_params: pbes2::Parameters,
password: impl AsRef<[u8]>,
doc: &[u8],
Expand Down
15 changes: 6 additions & 9 deletions pkcs8/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,20 @@ pub use spki::{
self, AlgorithmIdentifierRef, DecodePublicKey, SubjectPublicKeyInfo, SubjectPublicKeyInfoRef,
};

#[cfg(feature = "pem")]
pub use der::pem::LineEnding;
#[cfg(all(feature = "alloc", feature = "pkcs5"))]
pub use encrypted_private_key_info::EncryptedPrivateKeyInfoOwned;
#[cfg(feature = "encryption")]
pub use rand_core;
#[cfg(feature = "alloc")]
pub use {
crate::{private_key_info::allocating::PrivateKeyInfoOwned, traits::EncodePrivateKey},
der::{Document, SecretDocument},
spki::EncodePublicKey,
};

#[cfg(feature = "pem")]
pub use der::pem::LineEnding;

#[cfg(all(feature = "alloc", feature = "pkcs5"))]
pub use encrypted_private_key_info::EncryptedPrivateKeyInfoOwned;
#[cfg(feature = "pkcs5")]
pub use {
encrypted_private_key_info::{EncryptedPrivateKeyInfo, EncryptedPrivateKeyInfoRef},
pkcs5,
};

#[cfg(feature = "rand_core")]
pub use rand_core;
26 changes: 19 additions & 7 deletions pkcs8/src/private_key_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ where
PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a,
PubKey: BitStringLike,
{
/// Encrypt this private key using a symmetric encryption key derived
/// from the provided password.
/// Encrypt this private key using an encryption key derived from the provided password.
///
/// Uses the following algorithms for encryption:
/// - PBKDF: scrypt with default parameters:
Expand All @@ -149,18 +148,31 @@ where
/// # Errors
/// - Propagates errors from calling [`Encode::to_der`] on `Self`.
/// - Returns errors in the event encryption failed.
#[cfg(feature = "getrandom")]
pub fn encrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> {
let der = Zeroizing::new(self.to_der()?);
EncryptedPrivateKeyInfoRef::encrypt(password, der.as_ref())
}

/// Encrypt this private key using an encryption key derived from the provided password.
///
/// This function allows the RNG used to derive the salt/IV to be specified directly.
///
/// # Errors
/// - Propagates errors from calling [`Encode::to_der`] on `Self`.
/// - Returns errors in the event encryption failed.
#[cfg(feature = "encryption")]
pub fn encrypt<R: TryCryptoRng>(
pub fn encrypt_with_rng<R: TryCryptoRng>(
&self,
rng: &mut R,
password: impl AsRef<[u8]>,
) -> Result<SecretDocument> {
let der = Zeroizing::new(self.to_der()?);
EncryptedPrivateKeyInfoRef::encrypt(rng, password, der.as_ref())
EncryptedPrivateKeyInfoRef::encrypt_with_rng(rng, password, der.as_ref())
}

/// Encrypt this private key using a symmetric encryption key derived
/// from the provided password and [`pbes2::Parameters`].
/// Encrypt this private key using a symmetric encryption key derived from the provided password
/// and [`pbes2::Parameters`].
///
/// # Errors
/// - Propagates errors from calling [`Encode::to_der`] on `Self`.
Expand All @@ -172,7 +184,7 @@ where
password: impl AsRef<[u8]>,
) -> Result<SecretDocument> {
let der = Zeroizing::new(self.to_der()?);
EncryptedPrivateKeyInfoRef::encrypt_with(pbes2_params, password, der.as_ref())
EncryptedPrivateKeyInfoRef::encrypt_with_params(pbes2_params, password, der.as_ref())
}
}

Expand Down
23 changes: 9 additions & 14 deletions pkcs8/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{Error, PrivateKeyInfoRef, Result};
use der::SecretDocument;

#[cfg(feature = "encryption")]
use {crate::EncryptedPrivateKeyInfoRef, rand_core::TryCryptoRng};
use crate::EncryptedPrivateKeyInfoRef;

#[cfg(feature = "pem")]
use {
Expand Down Expand Up @@ -130,13 +130,9 @@ pub trait EncodePrivateKey {
/// # Errors
/// - Returns format-specific errors in the event the document failed to serialize.
/// - Returns algorithm-specific errors in the event the document couldn't be encrypted.
#[cfg(feature = "encryption")]
fn to_pkcs8_encrypted_der<R: TryCryptoRng>(
&self,
rng: &mut R,
password: impl AsRef<[u8]>,
) -> Result<SecretDocument> {
EncryptedPrivateKeyInfoRef::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes())
#[cfg(feature = "getrandom")]
fn to_pkcs8_encrypted_der(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> {
EncryptedPrivateKeyInfoRef::encrypt(password, self.to_pkcs8_der()?.as_bytes())
}

/// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`].
Expand All @@ -150,20 +146,19 @@ pub trait EncodePrivateKey {
Ok(doc.to_pem(PrivateKeyInfoRef::PEM_LABEL, line_ending)?)
}

/// Serialize this private key as an encrypted PEM-encoded PKCS#8 private
/// key using the `provided` to derive an encryption key.
/// Serialize this private key as an encrypted PEM-encoded PKCS#8 private key using the
/// `provided` to derive an encryption key.
///
/// # Errors
/// - Returns the same errors as [`EncodePrivateKey::to_pkcs8_encrypted_der`].
/// - Returns the same errors as [`SecretDocument::to_pem`].
#[cfg(all(feature = "encryption", feature = "pem"))]
fn to_pkcs8_encrypted_pem<R: TryCryptoRng>(
#[cfg(all(feature = "getrandom", feature = "pem"))]
fn to_pkcs8_encrypted_pem(
&self,
rng: &mut R,
password: impl AsRef<[u8]>,
line_ending: LineEnding,
) -> Result<Zeroizing<String>> {
let doc = self.to_pkcs8_encrypted_der(rng, password)?;
let doc = self.to_pkcs8_encrypted_der(password)?;
Ok(doc.to_pem(EncryptedPrivateKeyInfoRef::PEM_LABEL, line_ending)?)
}

Expand Down
Loading