diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c60be2c6625e..28d97a84860d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,16 @@ Changelog ========= +.. _v45-0-3: + +45.0.3 - 2025-05-25 +~~~~~~~~~~~~~~~~~~~ + +* Fixed decrypting PKCS#8 files encrypted with long salts (this impacts keys + encrypted by Bouncy Castle). +* Fixed decrypting PKCS#8 files encrypted with DES-CBC-MD5. While wildly + insecure, this remains prevalent. + .. _v45-0-2: 45.0.2 - 2025-05-17 @@ -37,6 +47,24 @@ Changelog provided (previously no exception was raised), and raises a ``TypeError`` if the key is encrypted but no password is provided (previously a ``ValueError`` was raised). +* Added ``__copy__`` to the + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`, and + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey` + abstract base classes. * We significantly refactored how private key loading ( :func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key` and diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 3392fde444f3..6c5a7e738853 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -285,6 +285,11 @@ Custom asymmetric vectors RSA key in an encrypted PEM with a malformed IV (not valid hex). * ``asymmetric/Traditional_OpenSSL_Serialization/key1-short-iv.pem`` - An RSA key in an encrypted PEM with an IV that's too short (less than 8 bytes). +* ``asymmetric/PKCS8/rsa-pbewithmd5anddescbc.pem`` - A PKCS8 encoded RSA key + encrypted using the ``pbeWithMD5AndDES-CBC`` algorithm with the password + ``hunter2``. +* ``asymmetric/PKCS8/rsa-pbe-3des-long-salt.pem`` - A PKCS8 encoded RSA key + encrypted with a 20 byte salt with the password ``password``. Key exchange ~~~~~~~~~~~~ diff --git a/docs/hazmat/decrepit/ciphers.rst b/docs/hazmat/decrepit/ciphers.rst index 8ae0178df2f1..5a3b2a50f396 100644 --- a/docs/hazmat/decrepit/ciphers.rst +++ b/docs/hazmat/decrepit/ciphers.rst @@ -4,7 +4,7 @@ Decrepit Symmetric algorithms ============================= -.. module:: cryptography.hazmat.decrepit.ciphers +.. module:: cryptography.hazmat.decrepit.ciphers.algorithms This module contains decrepit symmetric encryption algorithms. These are algorithms that should not be used unless necessary for backwards diff --git a/pyproject.toml b/pyproject.toml index 0ba49aa502a4..d94a1f5f98e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ build-backend = "maturin" [project] name = "cryptography" -version = "45.0.2" +version = "45.0.3" authors = [ { name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org" }, ] @@ -65,7 +65,7 @@ ssh = ["bcrypt >=3.1.5"] # All the following are used for our own testing. nox = ["nox >=2024.04.15", "nox[uv] >=2024.03.02; python_version >= '3.8'"] test = [ - "cryptography_vectors==45.0.2", + "cryptography_vectors==45.0.3", "pytest >=7.4.0", "pytest-benchmark >=4.0", "pytest-cov >=2.10.1", diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 610cb165135d..c430602486aa 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -10,7 +10,7 @@ "__version__", ] -__version__ = "45.0.2" +__version__ = "45.0.3" __author__ = "The Python Cryptographic Authority and individual contributors" diff --git a/src/cryptography/hazmat/decrepit/ciphers/algorithms.py b/src/cryptography/hazmat/decrepit/ciphers/algorithms.py index a7d4aa3c5d87..072a99143d6e 100644 --- a/src/cryptography/hazmat/decrepit/ciphers/algorithms.py +++ b/src/cryptography/hazmat/decrepit/ciphers/algorithms.py @@ -40,6 +40,11 @@ def key_size(self) -> int: return len(self.key) * 8 +# Not actually supported, marker for tests +class _DES: + key_size = 64 + + class Blowfish(BlockCipherAlgorithm): name = "Blowfish" block_size = 64 diff --git a/src/rust/cryptography-crypto/src/pbkdf1.rs b/src/rust/cryptography-crypto/src/pbkdf1.rs index 9a0cda4a116a..7a5bad23e423 100644 --- a/src/rust/cryptography-crypto/src/pbkdf1.rs +++ b/src/rust/cryptography-crypto/src/pbkdf1.rs @@ -30,9 +30,37 @@ pub fn openssl_kdf( Ok(key) } +/// PBKDF1 as defined in RFC 2898 for PKCS#5 v1.5 PBE algorithms +pub fn pbkdf1( + hash_alg: openssl::hash::MessageDigest, + password: &[u8], + salt: [u8; 8], + iterations: u64, + length: usize, +) -> Result, openssl::error::ErrorStack> { + if length > hash_alg.size() || iterations == 0 { + return Err(openssl::error::ErrorStack::get()); + } + + let mut h = openssl::hash::Hasher::new(hash_alg)?; + h.update(password)?; + h.update(&salt)?; + let mut t = h.finish()?; + + // Apply hash function for specified iterations + for _ in 1..iterations { + let mut h = openssl::hash::Hasher::new(hash_alg)?; + h.update(&t)?; + t = h.finish()?; + } + + // Return the first `length` bytes + Ok(t[..length].to_vec()) +} + #[cfg(test)] mod tests { - use super::openssl_kdf; + use super::{openssl_kdf, pbkdf1}; #[test] fn test_openssl_kdf() { @@ -98,4 +126,10 @@ mod tests { assert_eq!(key, expected); } } + + #[test] + fn test_pbkdf1() { + assert!(pbkdf1(openssl::hash::MessageDigest::md5(), b"abc", [0; 8], 1, 20).is_err()); + assert!(pbkdf1(openssl::hash::MessageDigest::md5(), b"abc", [0; 8], 0, 8).is_err()); + } } diff --git a/src/rust/cryptography-key-parsing/src/pkcs8.rs b/src/rust/cryptography-key-parsing/src/pkcs8.rs index 5d0dafd5c7e7..06634ae51a0f 100644 --- a/src/rust/cryptography-key-parsing/src/pkcs8.rs +++ b/src/rust/cryptography-key-parsing/src/pkcs8.rs @@ -2,7 +2,9 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use cryptography_x509::common::{AlgorithmIdentifier, AlgorithmParameters, PBES1Params}; +use cryptography_x509::common::{ + AlgorithmIdentifier, AlgorithmParameters, PbeParams, Pkcs12PbeParams, +}; use cryptography_x509::csr::Attributes; use cryptography_x509::pkcs8::EncryptedPrivateKeyInfo; @@ -122,19 +124,19 @@ pub fn parse_private_key( } } -fn pbes1_decrypt( +fn pkcs12_pbe_decrypt( data: &[u8], password: &[u8], cipher: openssl::symm::Cipher, hash: openssl::hash::MessageDigest, - params: &PBES1Params, + params: &Pkcs12PbeParams<'_>, ) -> 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 +144,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(), @@ -153,6 +155,31 @@ fn pbes1_decrypt( .map_err(|_| KeyParsingError::IncorrectPassword) } +fn pkcs5_pbe_decrypt( + data: &[u8], + password: &[u8], + cipher: openssl::symm::Cipher, + hash: openssl::hash::MessageDigest, + params: &PbeParams, +) -> KeyParsingResult> { + // PKCS#5 v1.5 uses PBKDF1 with iteration count + // For PKCS#5 PBE, we need key + IV length + let key_iv_len = cipher.key_len() + cipher.iv_len().unwrap(); + let key_iv = cryptography_crypto::pbkdf1::pbkdf1( + hash, + password, + params.salt, + params.iterations, + key_iv_len, + )?; + + let key = &key_iv[..cipher.key_len()]; + let iv = &key_iv[cipher.key_len()..]; + + openssl::symm::decrypt(cipher, key, Some(iv), data) + .map_err(|_| KeyParsingError::IncorrectPassword) +} + pub fn parse_encrypted_private_key( data: &[u8], password: Option<&[u8]>, @@ -164,7 +191,14 @@ pub fn parse_encrypted_private_key( }; let plaintext = match epki.encryption_algorithm.params { - AlgorithmParameters::Pbes1WithShaAnd3KeyTripleDesCbc(params) => pbes1_decrypt( + AlgorithmParameters::PbeWithMd5AndDesCbc(params) => pkcs5_pbe_decrypt( + epki.encrypted_data, + password, + openssl::symm::Cipher::des_cbc(), + openssl::hash::MessageDigest::md5(), + ¶ms, + )?, + AlgorithmParameters::PbeWithShaAnd3KeyTripleDesCbc(params) => pkcs12_pbe_decrypt( epki.encrypted_data, password, openssl::symm::Cipher::des_ede3_cbc(), @@ -172,7 +206,7 @@ pub fn parse_encrypted_private_key( ¶ms, )?, #[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_RC2"))] - AlgorithmParameters::Pbe1WithShaAnd40BitRc2Cbc(params) => pbes1_decrypt( + AlgorithmParameters::PbeWithShaAnd40BitRc2Cbc(params) => pkcs12_pbe_decrypt( epki.encrypted_data, password, openssl::symm::Cipher::rc2_40_cbc(), diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 0479653d95d4..183633b4a6ff 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -165,10 +165,12 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::RC2_CBC)] Rc2Cbc(Rc2CbcParams), - #[defined_by(oid::PBES1_WITH_SHA_AND_3KEY_TRIPLEDES_CBC)] - Pbes1WithShaAnd3KeyTripleDesCbc(PBES1Params), - #[defined_by(oid::PBES1_WITH_SHA_AND_40_BIT_RC2_CBC)] - Pbe1WithShaAnd40BitRc2Cbc(PBES1Params), + #[defined_by(oid::PBE_WITH_MD5_AND_DES_CBC)] + PbeWithMd5AndDesCbc(PbeParams), + #[defined_by(oid::PBE_WITH_SHA_AND_3KEY_TRIPLEDES_CBC)] + PbeWithShaAnd3KeyTripleDesCbc(Pkcs12PbeParams<'a>), + #[defined_by(oid::PBE_WITH_SHA_AND_40_BIT_RC2_CBC)] + PbeWithShaAnd40BitRc2Cbc(Pkcs12PbeParams<'a>), #[default] Other(asn1::ObjectIdentifier, Option>), @@ -529,12 +531,20 @@ pub struct ScryptParams<'a> { pub key_length: Option, } +// RFC 8018 Appendix A.3 #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug)] -pub struct PBES1Params { +pub struct PbeParams { pub salt: [u8; 8], pub iterations: u64, } +// From RFC 7202 Appendix C +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug)] +pub struct Pkcs12PbeParams<'a> { + pub salt: &'a [u8], + pub iterations: u64, +} + #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone, Debug)] pub struct Rc2CbcParams { pub version: Option, diff --git a/src/rust/cryptography-x509/src/oid.rs b/src/rust/cryptography-x509/src/oid.rs index 663673f4e76a..55e2e4573636 100644 --- a/src/rust/cryptography-x509/src/oid.rs +++ b/src/rust/cryptography-x509/src/oid.rs @@ -152,11 +152,12 @@ pub const EKU_CERTIFICATE_TRANSPARENCY_OID: asn1::ObjectIdentifier = pub const PBES2_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 5, 13); pub const PBKDF2_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 5, 12); +pub const PBE_WITH_MD5_AND_DES_CBC: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 5, 3); pub const SCRYPT_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 4, 1, 11591, 4, 11); -pub const PBES1_WITH_SHA_AND_3KEY_TRIPLEDES_CBC: asn1::ObjectIdentifier = +pub const PBE_WITH_SHA_AND_3KEY_TRIPLEDES_CBC: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 12, 1, 3); -pub const PBES1_WITH_SHA_AND_40_BIT_RC2_CBC: asn1::ObjectIdentifier = +pub const PBE_WITH_SHA_AND_40_BIT_RC2_CBC: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 12, 1, 6); pub const AES_128_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 1, 2); diff --git a/src/rust/src/backend/cipher_registry.rs b/src/rust/src/backend/cipher_registry.rs index 517995e8f2ca..92b9c600aea1 100644 --- a/src/rust/src/backend/cipher_registry.rs +++ b/src/rust/src/backend/cipher_registry.rs @@ -123,6 +123,7 @@ fn get_cipher_registry( let aes128 = types::AES128.get(py)?; let aes256 = types::AES256.get(py)?; let triple_des = types::TRIPLE_DES.get(py)?; + let des = types::DES.get(py)?; #[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_CAMELLIA"))] let camellia = types::CAMELLIA.get(py)?; #[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_BF"))] @@ -306,6 +307,8 @@ fn get_cipher_registry( #[cfg(not(CRYPTOGRAPHY_OSSLCONF = "OPENSSL_NO_RC4"))] m.add(&arc4, none_type.as_any(), None, Cipher::rc4())?; + m.add(&des, &cbc, Some(64), Cipher::des_cbc())?; + if let Some(rc2_cbc) = Cipher::from_nid(openssl::nid::Nid::RC2_CBC) { m.add(&rc2, &cbc, Some(128), rc2_cbc)?; } diff --git a/src/rust/src/pkcs12.rs b/src/rust/src/pkcs12.rs index 8f8e2d3c58f5..b31c6aa412e7 100644 --- a/src/rust/src/pkcs12.rs +++ b/src/rust/src/pkcs12.rs @@ -112,14 +112,14 @@ pub(crate) fn symmetric_encrypt( } enum EncryptionAlgorithm { - PBESv1SHA1And3KeyTripleDESCBC, + PBESHA1And3KeyTripleDESCBC, PBESv2SHA256AndAES256CBC, } impl EncryptionAlgorithm { fn salt_length(&self) -> usize { match self { - EncryptionAlgorithm::PBESv1SHA1And3KeyTripleDESCBC => 8, + EncryptionAlgorithm::PBESHA1And3KeyTripleDESCBC => 8, EncryptionAlgorithm::PBESv2SHA256AndAES256CBC => 16, } } @@ -131,11 +131,11 @@ impl EncryptionAlgorithm { iv: &'a [u8], ) -> cryptography_x509::common::AlgorithmIdentifier<'a> { match self { - EncryptionAlgorithm::PBESv1SHA1And3KeyTripleDESCBC => { + EncryptionAlgorithm::PBESHA1And3KeyTripleDESCBC => { cryptography_x509::common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: cryptography_x509::common::AlgorithmParameters::Pbes1WithShaAnd3KeyTripleDesCbc(cryptography_x509::common::PBES1Params{ - salt: salt[..8].try_into().unwrap(), + params: cryptography_x509::common::AlgorithmParameters::PbeWithShaAnd3KeyTripleDesCbc(cryptography_x509::common::Pkcs12PbeParams{ + salt, iterations: cipher_kdf_iter, }), } @@ -189,7 +189,7 @@ impl EncryptionAlgorithm { data: &[u8], ) -> CryptographyResult> { match self { - EncryptionAlgorithm::PBESv1SHA1And3KeyTripleDESCBC => { + EncryptionAlgorithm::PBESHA1And3KeyTripleDESCBC => { let key = cryptography_crypto::pkcs12::kdf( password, salt, @@ -341,7 +341,7 @@ fn decode_encryption_algorithm<'a>( let key_cert_alg = encryption_algorithm.getattr(pyo3::intern!(py, "_key_cert_algorithm"))?; let cipher = if key_cert_alg.is(&types::PBES_PBESV1SHA1AND3KEYTRIPLEDESCBC.get(py)?) { - EncryptionAlgorithm::PBESv1SHA1And3KeyTripleDESCBC + EncryptionAlgorithm::PBESHA1And3KeyTripleDESCBC } else if key_cert_alg.is(&types::PBES_PBESV2SHA256ANDAES256CBC.get(py)?) { EncryptionAlgorithm::PBESv2SHA256AndAES256CBC } else { diff --git a/src/rust/src/types.rs b/src/rust/src/types.rs index a449949bb7e6..7fb640d0daf5 100644 --- a/src/rust/src/types.rs +++ b/src/rust/src/types.rs @@ -515,6 +515,8 @@ pub static TRIPLE_DES: LazyPyImport = LazyPyImport::new( "cryptography.hazmat.decrepit.ciphers.algorithms", &["TripleDES"], ); +pub static DES: LazyPyImport = + LazyPyImport::new("cryptography.hazmat.decrepit.ciphers.algorithms", &["_DES"]); pub static AES: LazyPyImport = LazyPyImport::new( "cryptography.hazmat.primitives.ciphers.algorithms", &["AES"], diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 70062f156f17..119fb4d49c6e 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -11,7 +11,7 @@ import pytest from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography.hazmat.decrepit.ciphers.algorithms import RC2 +from cryptography.hazmat.decrepit.ciphers.algorithms import _DES, RC2 from cryptography.hazmat.primitives.asymmetric import ( dsa, ec, @@ -22,7 +22,7 @@ x25519, ) from cryptography.hazmat.primitives.ciphers import modes -from cryptography.hazmat.primitives.hashes import SHA1 +from cryptography.hazmat.primitives.hashes import MD5, SHA1 from cryptography.hazmat.primitives.serialization import ( BestAvailableEncryption, Encoding, @@ -463,6 +463,20 @@ 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_pbes_long_salt(self): + data = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "rsa-pbe-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", [ @@ -559,6 +573,20 @@ def test_load_pkcs8_scrypt(self): ) assert isinstance(key, ed25519.Ed25519PrivateKey) + @pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(MD5()) + and backend.cipher_supported(_DES(), modes.CBC(b"\x00" * 8)), + skip_message="Does not support DES MD5", + ) + def test_load_pkcs8_pbe_with_md5_and_des_cbc(self): + key = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "rsa-pbewithmd5anddescbc.pem"), + lambda f: load_pem_private_key(f.read(), password=b"hunter2"), + mode="rb", + ) + assert isinstance(key, rsa.RSAPrivateKey) + assert key.key_size == 2048 + class TestPEMSerialization: @pytest.mark.parametrize( diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index d108ab684d0d..1de1efd7c20b 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -6,4 +6,4 @@ "__version__", ] -__version__ = "45.0.2" +__version__ = "45.0.3" diff --git a/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbe-3des-long-salt.pem b/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbe-3des-long-salt.pem new file mode 100644 index 000000000000..0ea24f106673 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbe-3des-long-salt.pem @@ -0,0 +1,53 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +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 +2oCgLQpMQl9P+qBepCyRjb3ZiUS7KgVukhI= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbewithmd5anddescbc.pem b/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbewithmd5anddescbc.pem new file mode 100644 index 000000000000..31e35e30b2f6 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/PKCS8/rsa-pbewithmd5anddescbc.pem @@ -0,0 +1,29 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIE6TAbBgkqhkiG9w0BBQMwDgQIhYYzsDWw6gECAggABIIEyA65HvBbm8RHj7j3 +dMlCfZYpQ+xJ29e2XbrNj6aRLPMAndfz0LGaMS5CC0+DVNyrBAaqCxftFikwBItC +3fIPewrj6RjDBafxJcKpMx2dP5nj1tZk/e0RQqdCk6X2dQmlsB6P+wz0WOyFjrs2 +YMoWwaXkZcdtcmUvsrtT/Y+iiIlS6sCl1xHuaGEV06TjZWsUkL3NbZvYDc+2PVIQ +uPTDEidgOLWRz7b7k0Q1lEhhnU5VtFGHvPrfo7WDg88TXu37D2hp4GmRL3fvI9r5 +bLkMBn6R4trULqE2paggq8xW/7/RfrLSDgtlRGytOAMcvDRDQxotQgvyP6d+SYIh +xlUsl3HhsjLz8LqdaMLNIU2XqgmPyFNKiH8/Zva4Snw/ZL3LkqQNcPUjM7XqU6qk +jxH1sKIaiPE4bXb+WhhGkg91EsQz313S72tYyglcXMTkkgT5qg/ogujbimtjDvBo +EWgtAI4pNw1DYJsMh8fzbYINVn2r21OKhOaL/j/kZyn0oIrnfFEnCoQf3BrjUwnm +ErhpfDcPpq/WlmOipQHOh/AiydFj0KNVn5Z8DAxTSwnkR4jQE0ZUIMDm66g4x5hD +xdNSxiKkNVDfAARxSRkSKdyZoZgZPVLLW1PuEk+AaC/WrcU0K5eMM1HKOwUAxs3H +f5if/FPF6dI1Wn5/X0GAFWA03B1lotO6R2dthAYedjV7gSZoqKfDNhMFqdAfnZg6 +u/2yIYqcSAcmXISJlCeNjZa6Yk6GbzVdUDCPTacwonwoKeNR09guzYVGmjFBdJVq +CwUgWnQdrvc+lmLLie70d84zicLBwaAdRD+XiaRCzjVcg4XOn1pTd2aRzeTQP6Pm +rBCcgobD1VcTN6SpyDbh9xep0IRvLJqtVrA0XJoXwSImkHUNFPPUmHHaFpOx2CJL +bUj/QuYRKiTaNG78YEx6LfNdldfYKGcQs7ntqK6LJ3ZI6ll4mMEU7KoAIx9HLe77 +HQFpBE4zCOfGlmtkUv6iDyHI3T/KE5xIx6SjxQC3LgbK0UyJLXEGabv3mXNwOixm +ixj+pmlSeJgZodIJ0ySEOZealDUqiPZ5OLJA9S1YUzhkNwWqgBwBVVWrh+ZptiRy +kUXZRHd9RLM1I80jQavaWtclqbjpKcnsVtZgKTvL0nCQ2obeKkhkrGmW9gZ75mW7 +qZ6ZhAEEM7Woq8x2228e9SY2sLUS1F8HX0gSxgeZcj2Pu/yNVEiueUbA5sDHny8w +nCKcFO2YoJCuy9N5vSGI4oLrfkhYLGD4T49WWHbQ1FxiuXJyHyMvOic3+nvbSXg9 +CV8VDTJt0M+t2cfQI1HXtDmtzzZBad2BTcWkp8bK+uaknIkWcvMrOtCQv4s6Weev +9IfDAbVSFTziZhTQkOTMOQl7bRvJxdDWvIU6vJPbvU/1G/k5aT84EgSodsQOiRWP +GCPtd1Ky3r0/q5Wn9YVWLZ1J8lojMeZXRb30rb702Fr88E2EpEXm3LRDtWa04y7M +pzuzrt3wzjG4FtTG6M8i4iZuFhAiRnbpcQAYJzpsAnd7CDhAl1SB8HaUTJAkdP6L +dTPRsndlkMtkW+mgGjiQOh8DKLJyxIsPa42ZSDMxf/y+DVBGAWmdQnlI9R3ejfw0 +FQtb3ngwMaEa63Eiag== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/vectors/pyproject.toml b/vectors/pyproject.toml index 4f3a671b9d61..02e190c8665c 100644 --- a/vectors/pyproject.toml +++ b/vectors/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi" [project] name = "cryptography_vectors" -version = "45.0.2" +version = "45.0.3" authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ]