diff --git a/Cargo.lock b/Cargo.lock index 66028a96c..3eeeb432c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1052,6 +1052,7 @@ version = "0.11.0-rc.11" dependencies = [ "ctutils", "der", + "getrandom 0.4.2", "hex-literal", "pkcs5", "rand_core 0.10.1", diff --git a/pkcs8/Cargo.toml b/pkcs8/Cargo.toml index 7755f919e..48f1ff409 100644 --- a/pkcs8/Cargo.toml +++ b/pkcs8/Cargo.toml @@ -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 } @@ -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"] diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index 91b99d680..6cf79ee20 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -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 { + 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( + pub(crate) fn encrypt_with_rng( rng: &mut R, password: impl AsRef<[u8]>, doc: &[u8], ) -> Result { 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], diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index a5242e6f4..88e81a314 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -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; diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 50d0fb148..2b61c0344 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -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: @@ -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 { + 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( + pub fn encrypt_with_rng( &self, rng: &mut R, password: impl AsRef<[u8]>, ) -> Result { 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`. @@ -172,7 +184,7 @@ where password: impl AsRef<[u8]>, ) -> Result { 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()) } } diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index 1bf738d48..9267a8978 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -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 { @@ -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( - &self, - rng: &mut R, - password: impl AsRef<[u8]>, - ) -> Result { - EncryptedPrivateKeyInfoRef::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes()) + #[cfg(feature = "getrandom")] + fn to_pkcs8_encrypted_der(&self, password: impl AsRef<[u8]>) -> Result { + EncryptedPrivateKeyInfoRef::encrypt(password, self.to_pkcs8_der()?.as_bytes()) } /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`]. @@ -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( + #[cfg(all(feature = "getrandom", feature = "pem"))] + fn to_pkcs8_encrypted_pem( &self, - rng: &mut R, password: impl AsRef<[u8]>, line_ending: LineEnding, ) -> Result> { - 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)?) }