diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index a02fb24005b2..5d92d7160956 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -288,6 +288,8 @@ Custom asymmetric vectors * ``asymmetric/PKCS8/rsa-pbewithmd5anddescbc.pem`` - A PKCS8 encoded RSA key encrypted using the ``pbeWithMD5AndDES-CBC`` algorithm with the password ``hunter2``. +* ``asymmetric/PKCS8/rsa-pbes1-3des-long-salt.pem`` - A PKCS8 encoded RSA key + encrypted with a 20 byte salt with the password ``password``. Key exchange ~~~~~~~~~~~~ diff --git a/src/rust/cryptography-key-parsing/src/pkcs8.rs b/src/rust/cryptography-key-parsing/src/pkcs8.rs index 5d0dafd5c7e7..05809af99a26 100644 --- a/src/rust/cryptography-key-parsing/src/pkcs8.rs +++ b/src/rust/cryptography-key-parsing/src/pkcs8.rs @@ -127,14 +127,14 @@ fn pbes1_decrypt( password: &[u8], cipher: openssl::symm::Cipher, hash: openssl::hash::MessageDigest, - params: &PBES1Params, + params: &PBES1Params<'_>, ) -> KeyParsingResult> { let Ok(password) = std::str::from_utf8(password) else { return Err(KeyParsingError::IncorrectPassword); }; let key = cryptography_crypto::pkcs12::kdf( password, - ¶ms.salt, + params.salt, cryptography_crypto::pkcs12::KDF_ENCRYPTION_KEY_ID, params.iterations, cipher.key_len(), @@ -142,7 +142,7 @@ fn pbes1_decrypt( )?; let iv = cryptography_crypto::pkcs12::kdf( password, - ¶ms.salt, + params.salt, cryptography_crypto::pkcs12::KDF_IV_ID, params.iterations, cipher.block_size(), diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 0479653d95d4..414f97083ac9 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -166,9 +166,9 @@ pub enum AlgorithmParameters<'a> { Rc2Cbc(Rc2CbcParams), #[defined_by(oid::PBES1_WITH_SHA_AND_3KEY_TRIPLEDES_CBC)] - Pbes1WithShaAnd3KeyTripleDesCbc(PBES1Params), + Pbes1WithShaAnd3KeyTripleDesCbc(PBES1Params<'a>), #[defined_by(oid::PBES1_WITH_SHA_AND_40_BIT_RC2_CBC)] - Pbe1WithShaAnd40BitRc2Cbc(PBES1Params), + Pbe1WithShaAnd40BitRc2Cbc(PBES1Params<'a>), #[default] Other(asn1::ObjectIdentifier, Option>), @@ -529,9 +529,16 @@ pub struct ScryptParams<'a> { pub key_length: Option, } +// PBES1Params is defined as +// PBEParameter ::= SEQUENCE { +// salt OCTET STRING (SIZE(8)), +// iterationCount INTEGER +// } +// in RFC 2898 and 8018 but in practice various implementations +// use longer salts, so we need to handle variable salt length. #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug)] -pub struct PBES1Params { - pub salt: [u8; 8], +pub struct PBES1Params<'a> { + pub salt: &'a [u8], pub iterations: u64, } diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 70062f156f17..33046543e1e5 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -463,6 +463,22 @@ def test_load_pkcs8_private_key_unknown_kdf(self): with pytest.raises(ValueError): load_pem_private_key(data, password=b"password") + @pytest.mark.skip_fips(reason="3DES unsupported in FIPS") + def test_load_pkcs8_pbes1_long_salt(self): + data = load_vectors_from_file( + os.path.join( + "asymmetric", "PKCS8", "rsa-pbes1-3des-long-salt.pem" + ), + lambda f: f.read(), + mode="rb", + ) + key = load_pem_private_key( + data, password=b"password", unsafe_skip_rsa_key_validation=True + ) + assert isinstance(key, rsa.RSAPrivateKey) + assert key.key_size == 4096 + assert key.private_numbers().public_numbers.e == 65537 + @pytest.mark.parametrize( "filename", [ diff --git a/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbes1-3des-long-salt.pem b/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbes1-3des-long-salt.pem new file mode 100644 index 000000000000..0ea24f106673 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbes1-3des-long-salt.pem @@ -0,0 +1,53 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +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 +2oCgLQpMQl9P+qBepCyRjb3ZiUS7KgVukhI= +-----END ENCRYPTED PRIVATE KEY-----