Skip to content

Commit fe8438c

Browse files
alexclaude
andauthored
Implement encrypted PKCS#8 serialization using rust-asn1 (#13628)
Replace OpenSSL's private_key_to_pkcs8_passphrase with our own implementation in the cryptography-key-parsing crate. Uses PBES2 with PBKDF2-SHA256 (2048 iterations) and AES-256-CBC encryption. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent ed23465 commit fe8438c

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

src/rust/cryptography-key-parsing/src/pkcs8.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,71 @@ pub fn serialize_private_key(
457457
Ok(asn1::write_single(&pki)?)
458458
}
459459

460+
const KDF_ITERATION_COUNT: usize = 2048;
461+
462+
pub fn serialize_encrypted_private_key(
463+
pkey: &openssl::pkey::PKeyRef<openssl::pkey::Private>,
464+
password: &[u8],
465+
) -> crate::KeySerializationResult<Vec<u8>> {
466+
let plaintext_der = serialize_private_key(pkey)?;
467+
468+
let mut salt = [0u8; 16];
469+
let mut iv = [0u8; 16];
470+
cryptography_openssl::rand::rand_bytes(&mut salt)?;
471+
cryptography_openssl::rand::rand_bytes(&mut iv)?;
472+
473+
let cipher = openssl::symm::Cipher::aes_256_cbc();
474+
let mut key = [0u8; 32];
475+
openssl::pkcs5::pbkdf2_hmac(
476+
password,
477+
&salt,
478+
KDF_ITERATION_COUNT,
479+
openssl::hash::MessageDigest::sha256(),
480+
&mut key,
481+
)?;
482+
483+
let encrypted_data = openssl::symm::encrypt(cipher, &key, Some(&iv), &plaintext_der)?;
484+
485+
let kdf_algorithm = cryptography_x509::common::AlgorithmIdentifier {
486+
oid: asn1::DefinedByMarker::marker(),
487+
params: cryptography_x509::common::AlgorithmParameters::Pbkdf2(
488+
cryptography_x509::common::PBKDF2Params {
489+
salt: &salt,
490+
iteration_count: KDF_ITERATION_COUNT as u64,
491+
key_length: None,
492+
prf: Box::new(cryptography_x509::common::AlgorithmIdentifier {
493+
oid: asn1::DefinedByMarker::marker(),
494+
params: cryptography_x509::common::AlgorithmParameters::HmacWithSha256(
495+
Some(()),
496+
),
497+
}),
498+
},
499+
),
500+
};
501+
502+
let encryption_algorithm = cryptography_x509::common::AlgorithmIdentifier {
503+
oid: asn1::DefinedByMarker::marker(),
504+
params: cryptography_x509::common::AlgorithmParameters::Aes256Cbc(iv),
505+
};
506+
507+
let encryption_alg = cryptography_x509::common::AlgorithmIdentifier {
508+
oid: asn1::DefinedByMarker::marker(),
509+
params: cryptography_x509::common::AlgorithmParameters::Pbes2(
510+
cryptography_x509::common::PBES2Params {
511+
key_derivation_func: Box::new(kdf_algorithm),
512+
encryption_scheme: Box::new(encryption_algorithm),
513+
},
514+
),
515+
};
516+
517+
let epki = cryptography_x509::pkcs8::EncryptedPrivateKeyInfo {
518+
encryption_algorithm: encryption_alg,
519+
encrypted_data: &encrypted_data,
520+
};
521+
522+
Ok(asn1::write_single(&epki)?)
523+
}
524+
460525
#[cfg(test)]
461526
mod tests {
462527
use super::serialize_private_key;

src/rust/src/backend/utils.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,7 @@ pub(crate) fn pkey_private_bytes<'p>(
122122
} else {
123123
(
124124
"ENCRYPTED PRIVATE KEY",
125-
pkey.private_key_to_pkcs8_passphrase(
126-
openssl::symm::Cipher::aes_256_cbc(),
127-
password,
128-
)?,
125+
cryptography_key_parsing::pkcs8::serialize_encrypted_private_key(pkey, password)?,
129126
)
130127
};
131128

0 commit comments

Comments
 (0)