Skip to content

Commit 7d69c45

Browse files
authored
pkcs8: getrandom feature (#2311)
This crate needs randomness for PKCS#5 salt/IVs whenever encrypting a plaintext private key. This renames the encryption methods that take an explict RNG from `encrypt` => `encrypt_with_rng` e.g. `PrivateKeyInfo::encrypt_with_rng` and adds a new e.g. `PrivateKeyInfo::encrypt` method which uses `getrandom` to obtain randomness. The trait methods `EncodePrivateKey::to_pkcs8_encrypted_der` and `::to_pkcs8_encrypted_pem` have likewise been updated to require the `getrandom` feature.
1 parent 381e23c commit 7d69c45

6 files changed

Lines changed: 48 additions & 34 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkcs8/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ spki = "0.8"
2222

2323
# optional dependencies
2424
ctutils = { version = "0.4", optional = true }
25+
getrandom = { version = "0.4", optional = true, features = ["sys_rng"] }
2526
pkcs5 = { version = "0.8", optional = true, features = ["rand_core"] }
2627
rand_core = { version = "0.10", optional = true, default-features = false }
2728

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

3637
3des = ["encryption", "pkcs5/3des"]
3738
des-insecure = ["encryption", "pkcs5/des-insecure"]
38-
encryption = ["alloc", "pkcs5/alloc", "pkcs5/pbes2", "rand_core"]
39+
encryption = ["alloc", "pkcs5/alloc", "pkcs5/pbes2", "dep:rand_core"]
40+
getrandom = ["encryption", "pkcs5/getrandom", "dep:getrandom"]
3941
pem = ["alloc", "der/pem", "spki/pem"]
4042
sha1-insecure = ["encryption", "pkcs5/sha1-insecure"]
4143

pkcs8/src/encrypted_private_key_info.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,29 @@ where
6565
.try_into()?)
6666
}
6767

68+
/// Encrypt the given ASN.1 DER document using a symmetric encryption key
69+
/// derived from the provided password.
70+
#[cfg(feature = "getrandom")]
71+
pub(crate) fn encrypt(password: impl AsRef<[u8]>, doc: &[u8]) -> Result<SecretDocument> {
72+
Self::encrypt_with_rng(&mut getrandom::SysRng, password, doc)
73+
}
74+
6875
/// Encrypt the given ASN.1 DER document using a symmetric encryption key
6976
/// derived from the provided password.
7077
#[cfg(feature = "encryption")]
71-
pub(crate) fn encrypt<R: TryCryptoRng>(
78+
pub(crate) fn encrypt_with_rng<R: TryCryptoRng>(
7279
rng: &mut R,
7380
password: impl AsRef<[u8]>,
7481
doc: &[u8],
7582
) -> Result<SecretDocument> {
7683
let pbes2_params = pbes2::Parameters::generate_recommended(rng)?;
77-
EncryptedPrivateKeyInfoOwned::encrypt_with(pbes2_params, password, doc)
84+
EncryptedPrivateKeyInfoOwned::encrypt_with_params(pbes2_params, password, doc)
7885
}
7986

8087
/// Encrypt this private key using a symmetric encryption key derived
8188
/// from the provided password and [`pbes2::Parameters`].
8289
#[cfg(feature = "encryption")]
83-
pub(crate) fn encrypt_with(
90+
pub(crate) fn encrypt_with_params(
8491
pbes2_params: pbes2::Parameters,
8592
password: impl AsRef<[u8]>,
8693
doc: &[u8],

pkcs8/src/lib.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,20 @@ pub use spki::{
8787
self, AlgorithmIdentifierRef, DecodePublicKey, SubjectPublicKeyInfo, SubjectPublicKeyInfoRef,
8888
};
8989

90+
#[cfg(feature = "pem")]
91+
pub use der::pem::LineEnding;
92+
#[cfg(all(feature = "alloc", feature = "pkcs5"))]
93+
pub use encrypted_private_key_info::EncryptedPrivateKeyInfoOwned;
94+
#[cfg(feature = "encryption")]
95+
pub use rand_core;
9096
#[cfg(feature = "alloc")]
9197
pub use {
9298
crate::{private_key_info::allocating::PrivateKeyInfoOwned, traits::EncodePrivateKey},
9399
der::{Document, SecretDocument},
94100
spki::EncodePublicKey,
95101
};
96-
97-
#[cfg(feature = "pem")]
98-
pub use der::pem::LineEnding;
99-
100-
#[cfg(all(feature = "alloc", feature = "pkcs5"))]
101-
pub use encrypted_private_key_info::EncryptedPrivateKeyInfoOwned;
102102
#[cfg(feature = "pkcs5")]
103103
pub use {
104104
encrypted_private_key_info::{EncryptedPrivateKeyInfo, EncryptedPrivateKeyInfoRef},
105105
pkcs5,
106106
};
107-
108-
#[cfg(feature = "rand_core")]
109-
pub use rand_core;

pkcs8/src/private_key_info.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ where
136136
PubKey: DecodeValue<'a, Error = der::Error> + FixedTag + 'a,
137137
PubKey: BitStringLike,
138138
{
139-
/// Encrypt this private key using a symmetric encryption key derived
140-
/// from the provided password.
139+
/// Encrypt this private key using an encryption key derived from the provided password.
141140
///
142141
/// Uses the following algorithms for encryption:
143142
/// - PBKDF: scrypt with default parameters:
@@ -149,18 +148,31 @@ where
149148
/// # Errors
150149
/// - Propagates errors from calling [`Encode::to_der`] on `Self`.
151150
/// - Returns errors in the event encryption failed.
151+
#[cfg(feature = "getrandom")]
152+
pub fn encrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> {
153+
let der = Zeroizing::new(self.to_der()?);
154+
EncryptedPrivateKeyInfoRef::encrypt(password, der.as_ref())
155+
}
156+
157+
/// Encrypt this private key using an encryption key derived from the provided password.
158+
///
159+
/// This function allows the RNG used to derive the salt/IV to be specified directly.
160+
///
161+
/// # Errors
162+
/// - Propagates errors from calling [`Encode::to_der`] on `Self`.
163+
/// - Returns errors in the event encryption failed.
152164
#[cfg(feature = "encryption")]
153-
pub fn encrypt<R: TryCryptoRng>(
165+
pub fn encrypt_with_rng<R: TryCryptoRng>(
154166
&self,
155167
rng: &mut R,
156168
password: impl AsRef<[u8]>,
157169
) -> Result<SecretDocument> {
158170
let der = Zeroizing::new(self.to_der()?);
159-
EncryptedPrivateKeyInfoRef::encrypt(rng, password, der.as_ref())
171+
EncryptedPrivateKeyInfoRef::encrypt_with_rng(rng, password, der.as_ref())
160172
}
161173

162-
/// Encrypt this private key using a symmetric encryption key derived
163-
/// from the provided password and [`pbes2::Parameters`].
174+
/// Encrypt this private key using a symmetric encryption key derived from the provided password
175+
/// and [`pbes2::Parameters`].
164176
///
165177
/// # Errors
166178
/// - Propagates errors from calling [`Encode::to_der`] on `Self`.
@@ -172,7 +184,7 @@ where
172184
password: impl AsRef<[u8]>,
173185
) -> Result<SecretDocument> {
174186
let der = Zeroizing::new(self.to_der()?);
175-
EncryptedPrivateKeyInfoRef::encrypt_with(pbes2_params, password, der.as_ref())
187+
EncryptedPrivateKeyInfoRef::encrypt_with_params(pbes2_params, password, der.as_ref())
176188
}
177189
}
178190

pkcs8/src/traits.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{Error, PrivateKeyInfoRef, Result};
66
use der::SecretDocument;
77

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

1111
#[cfg(feature = "pem")]
1212
use {
@@ -130,13 +130,9 @@ pub trait EncodePrivateKey {
130130
/// # Errors
131131
/// - Returns format-specific errors in the event the document failed to serialize.
132132
/// - Returns algorithm-specific errors in the event the document couldn't be encrypted.
133-
#[cfg(feature = "encryption")]
134-
fn to_pkcs8_encrypted_der<R: TryCryptoRng>(
135-
&self,
136-
rng: &mut R,
137-
password: impl AsRef<[u8]>,
138-
) -> Result<SecretDocument> {
139-
EncryptedPrivateKeyInfoRef::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes())
133+
#[cfg(feature = "getrandom")]
134+
fn to_pkcs8_encrypted_der(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> {
135+
EncryptedPrivateKeyInfoRef::encrypt(password, self.to_pkcs8_der()?.as_bytes())
140136
}
141137

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

153-
/// Serialize this private key as an encrypted PEM-encoded PKCS#8 private
154-
/// key using the `provided` to derive an encryption key.
149+
/// Serialize this private key as an encrypted PEM-encoded PKCS#8 private key using the
150+
/// `provided` to derive an encryption key.
155151
///
156152
/// # Errors
157153
/// - Returns the same errors as [`EncodePrivateKey::to_pkcs8_encrypted_der`].
158154
/// - Returns the same errors as [`SecretDocument::to_pem`].
159-
#[cfg(all(feature = "encryption", feature = "pem"))]
160-
fn to_pkcs8_encrypted_pem<R: TryCryptoRng>(
155+
#[cfg(all(feature = "getrandom", feature = "pem"))]
156+
fn to_pkcs8_encrypted_pem(
161157
&self,
162-
rng: &mut R,
163158
password: impl AsRef<[u8]>,
164159
line_ending: LineEnding,
165160
) -> Result<Zeroizing<String>> {
166-
let doc = self.to_pkcs8_encrypted_der(rng, password)?;
161+
let doc = self.to_pkcs8_encrypted_der(password)?;
167162
Ok(doc.to_pem(EncryptedPrivateKeyInfoRef::PEM_LABEL, line_ending)?)
168163
}
169164

0 commit comments

Comments
 (0)