diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4735f42..779f442 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -26,7 +26,7 @@ Deprecations:
 Changes:
 ^^^^^^^^
 
-*none*
+- You can now load encrypted PKCS#8 PEM key as ``pem.Key``.
 
 
 ----
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index dcabac2..57802b5 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -18,6 +18,8 @@ Workflow
   Whether you prefer to rebase on master or merge master into your branch, do whatever is more comfortable for you.
 - *Always* add tests and docs for your code.
   This is a hard rule; patches with missing tests or documentation can't be merged.
+- Consider updating CHANGELOG.rst to reflect the changes as observed by people
+  using this library.
 - Make sure your changes pass our CI_.
   You won't get any feedback until it's green unless you ask for it.
 - Once you've addressed review feedback, make sure to bump the pull request with a short note, so we know you're done.
diff --git a/setup.cfg b/setup.cfg
index b0a9418..8aac42a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -24,4 +24,4 @@ multi_line_output=3
 not_skip=__init__.py
 
 known_first_party=pem
-known_third_party=OpenSSL,certifi,pem,pretend,pytest,setuptools,sphinx_rtd_theme,twisted
+known_third_party=OpenSSL,certifi,pem,pretend,pytest,setuptools,sphinx_rtd_theme,twisted,typing
diff --git a/src/pem/_core.py b/src/pem/_core.py
index 0acdce6..b3998d3 100644
--- a/src/pem/_core.py
+++ b/src/pem/_core.py
@@ -141,6 +141,7 @@ class DHParameters(AbstractPEMObject):
 _PEM_TO_CLASS = {
     b"CERTIFICATE": Certificate,
     b"PRIVATE KEY": Key,
+    b"ENCRYPTED PRIVATE KEY": Key,
     b"RSA PRIVATE KEY": RSAPrivateKey,
     b"DH PARAMETERS": DHParameters,
     b"NEW CERTIFICATE REQUEST": CertificateRequest,

Add support for PCKS#8 encrypted `BEGIN ENCRYPTED PRIVATE KEY`
It looks like for now only `RSA PRIVATE KEY` is supported.

OpenSSL docs https://www.openssl.org/docs/man1.0.2/apps/openssl-pkcs8.html

A comparison

https://github.com/kjur/jsrsasign/wiki/Tutorial-for-PKCS5-and-PKCS8-PEM-private-key-formats-differences

--------

I will try to add a patch, but for now I have created this issue for reference
diff --git a/tests/data.py b/tests/data.py
index 81f9b0f..5c82cc2 100644
--- a/tests/data.py
+++ b/tests/data.py
@@ -54,6 +54,75 @@ kjBF/mzooA==
 -----END RSA PRIVATE KEY-----
 """
 
+# KEY_PEM_PKCS8_* and KEY_PEM_PKCS5_* contain the same private key, but in
+# different formats.
+
+# PKCS#5 RSA unencrypted.
+# Generated with:
+# openssl genrsa -out private.pem 512
+KEY_PEM_PKCS5_UNENCRYPTED = b"""-----BEGIN RSA PRIVATE KEY-----
+MIIBOwIBAAJBAKX6cRhPHvdyoftEHGiRje3tTLRDnddg01AvgsJJcCFoIjwdgfa9
+aKFdzCcgD/htjvfRZl24M7E89sMUBMNHk8ECAwEAAQJABcBi8OO1AAAh6tIWZe09
+TNRfRxPcwVzilbG/xznCP/YMf72E8hsZazu+HGMKITg9dFeJOyjXZ4e8sD/pL/I6
+0QIhANzULu4JjJxpoTK8NnF/CemF7neLROA18NDB/mao5ZZtAiEAwGnYobinxuHS
+UQh8cT3w7aLsVlarZmCtoapxjW+ObiUCIQCcAltVV/G63vU/PrDH5hQ+opwiYIW8
+UN9c3HC6XkA00QIhAJ8YpfwKgAfNfyZrmuHTspv7Q+mb3jtXoxnyodOtsxpVAiBC
+a4FDqkr+bDwV4SwaGdG/AC40fR3P8hhOADAhtFDwlw==
+-----END RSA PRIVATE KEY-----
+"""
+
+# PKCS#5 RSA encrypted with `test` as password.
+# Generated with:
+# openssl genrsa -des3 -out private.pem 512
+KEY_PEM_PKCS5_ENCRYPTED = b"""-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,8A72BD2DC1C9092F
+
+6LgvCNeXdcuTayEOKhQo2N4IveCP0S3t8xJCeihW9yizLeQFzSjqSfKtmRyImjfg
+fMl8IMDFozR+xVE9uWaIo98wKWpjyu6cytYyjL/8SP3jswBoSP5P9OekUSLifPWM
+ghUEu6tGissqSs/8i2wzLIdho3DdUnUMPZIprENmK6HrYmdRtJT3qMgkFTCtCS9Q
+r9oPm7xKPsfKBhaUHK51JcsPkPjrny8Dl56W0IYf/dfvRPwSr5yFQFLk6Nbgnx0N
+32aT3ZMRCEvOTxhX1cO3f5JqYLxFAGKBFwvsulTisJ6rGYOEDSMBDwZc3sqLvt5g
+h0vKRPqSkylQ0W5shNg0bwbxySiRxJPBL8kWDAbJVfauArabLPuNkUNwmYhIjy7j
+lY0oYw2xeJ9hTUly/Zg3+DI8oYYY3z7WaxPHXEoicCE=
+-----END RSA PRIVATE KEY-----
+"""
+
+# PKCS#8 RSA encrypted with `test` as password.
+# Generated with pkc5 as intermediate file:
+# openssl genrsa -des3 -out private.pem 512
+# openssl pkcs8 -topk8 -in private.pem
+KEY_PEM_PKCS8_ENCRYPTED = b"""-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBvTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIyqwWErm7rlcCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAkVu+KRbmcfWIGKzgnjjBMBIIB
+YI3aRS0ebuzb1Tq26/HAq8pplPu+96dM1SnRNXwH0ijmP3fLBjEDH4hB/X9H8arT
+xWSfKQ80+FKI07DsLQKmO+cuB12MAWPSoCNBRtLwGUiwYvlMcBp6XR4NQQ+YG/Nw
+OgZ1InH2w7uSnDPdxV9dZculYWzJE82IohnFVZokO2nYSEfIqr1xVQZht6lfzpx2
+aRje42fpYfgkEm13w4oJKIlekzA9M4CeYku7Q4l9GDSHRmoeypMSHPI8RFV9pxub
+ME3AMXGcRioJ0Ic/cpmwqFaJbTVRPsqFVEsMCz1T/CQ4oLjPTWg+zkxfsPIyGj7L
+K3yLZmTA6IxSu+wuO/bsbqiM3x718AW6U0FHXd4zk+llu3mUfhTiMYPvN/cedv/M
+wsT85CHM6reIBopGMqeZD965tNEcWPGMEvXXnG71dxxgrfHFv7l/o8+moVRNIQCh
+EArlaXgT3MlI1jb9HoNvVNg=
+-----END ENCRYPTED PRIVATE KEY-----
+"""
+
+# RSA unencrypted
+# Generated with pkc5 as intermediate file:
+# openssl genrsa -des3 -out private.pem 512
+# openssl pkcs8 -topk8 -in private.pem -nocrypt
+KEY_PEM_PKCS8_UNENCRYPTED = b"""-----BEGIN PRIVATE KEY-----
+MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEApfpxGE8e93Kh+0Qc
+aJGN7e1MtEOd12DTUC+CwklwIWgiPB2B9r1ooV3MJyAP+G2O99FmXbgzsTz2wxQE
+w0eTwQIDAQABAkAFwGLw47UAACHq0hZl7T1M1F9HE9zBXOKVsb/HOcI/9gx/vYTy
+GxlrO74cYwohOD10V4k7KNdnh7ywP+kv8jrRAiEA3NQu7gmMnGmhMrw2cX8J6YXu
+d4tE4DXw0MH+Zqjllm0CIQDAadihuKfG4dJRCHxxPfDtouxWVqtmYK2hqnGNb45u
+JQIhAJwCW1VX8bre9T8+sMfmFD6inCJghbxQ31zccLpeQDTRAiEAnxil/AqAB81/
+Jmua4dOym/tD6ZveO1ejGfKh062zGlUCIEJrgUOqSv5sPBXhLBoZ0b8ALjR9Hc/y
+GE4AMCG0UPCX
+-----END PRIVATE KEY-----
+"""
+
+
 DH_PEM = b"""-----BEGIN DH PARAMETERS-----
 MIICCAKCAgEAj9/hwPNNKlQEANXqFBXViNy9nVpYlqIIHaLhoKdwAFzgYM+9hNSz
 FM/k+K5FS5dXrM63Zh9NgTI1M+ZRHJAxM2hhsG8AA333PN+c3exTRGwjQhU16XJg
diff --git a/tests/test_core.py b/tests/test_core.py
index 6e4349f..a9d5f17 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -6,6 +6,8 @@ from itertools import combinations
 
 import certifi
 
+from OpenSSL import crypto
+
 import pem
 
 from pem._compat import text_type
@@ -16,7 +18,10 @@ from .data import (
     CERT_PEMS_NO_NEW_LINE,
     CRL_PEMS,
     DH_PEM,
-    KEY_PEM,
+    KEY_PEM_PKCS5_ENCRYPTED,
+    KEY_PEM_PKCS5_UNENCRYPTED,
+    KEY_PEM_PKCS8_ENCRYPTED,
+    KEY_PEM_PKCS8_UNENCRYPTED,
 )
 
 
@@ -339,15 +344,76 @@ class TestPEMObjects(object):
 
 
 class TestParse(object):
-    def test_key(self):
+    """
+    Tests for parsing input with one or multiple PEM objects.
+    """
+
+    def test_key_pkcs5_unencrypted(self):
         """
-        Parses a PEM string with a key into an RSAPrivateKey.
+        It can load an unencrypted PKCS#5 RSA key as PEM string
+        as an RSAPrivateKey.
         """
-        rv = pem.parse(KEY_PEM)
+        rv = pem.parse(KEY_PEM_PKCS5_UNENCRYPTED)
         key, = rv
 
         assert isinstance(key, pem.RSAPrivateKey)
-        assert KEY_PEM == key.as_bytes()
+        assert KEY_PEM_PKCS5_UNENCRYPTED == key.as_bytes()
+
+        crypto_key = crypto.load_privatekey(
+            crypto.FILETYPE_PEM, key.as_bytes()
+        )
+        assert crypto.TYPE_RSA, crypto_key.type()
+        assert 512, crypto_key.bits()
+
+    def test_key_pkcs5_encrypted(self):
+        """
+        It can load an encrypted PKCS#5 RSA key as PEM string
+        as an RSAPrivateKey.
+        """
+        rv = pem.parse(KEY_PEM_PKCS5_ENCRYPTED)
+        key, = rv
+
+        assert isinstance(key, pem.RSAPrivateKey)
+        assert KEY_PEM_PKCS5_ENCRYPTED == key.as_bytes()
+
+        crypto_key = crypto.load_privatekey(
+            crypto.FILETYPE_PEM, key.as_bytes(), b"test"
+        )
+        assert crypto.TYPE_RSA, crypto_key.type()
+        assert 512, crypto_key.bits()
+
+    def test_key_pkcs8_unencrypted(self):
+        """
+        It can load an unencrypted PKCS#8 RSA key as PEM string
+        as an RSAPrivateKey.
+        """
+        rv = pem.parse(KEY_PEM_PKCS8_UNENCRYPTED)
+        key, = rv
+
+        assert isinstance(key, pem.Key)
+        assert KEY_PEM_PKCS8_UNENCRYPTED == key.as_bytes()
+
+        crypto_key = crypto.load_privatekey(
+            crypto.FILETYPE_PEM, key.as_bytes()
+        )
+        assert crypto.TYPE_RSA, crypto_key.type()
+        assert 512, crypto_key.bits()
+
+    def test_key_pkcs8_encrypted(self):
+        """
+        It can load an encrypted PKCS#8 RSA key as PEM string
+        as an RSAPrivateKey.
+        """
+        rv = pem.parse(KEY_PEM_PKCS8_ENCRYPTED)
+        key, = rv
+
+        assert isinstance(key, pem.Key)
+        assert KEY_PEM_PKCS8_ENCRYPTED == key.as_bytes()
+
+        crypto_key = crypto.load_privatekey(
+            crypto.FILETYPE_PEM, key.as_bytes(), b"test"
+        )
+        assert crypto.TYPE_RSA, crypto_key
 
     def test_certificates(self):
         """
@@ -423,7 +489,7 @@ class TestParse(object):
         """
         \n and \r\n are treated equal.
         """
-        lf_pem = KEY_PEM.replace(b"\n", b"\r\n")
+        lf_pem = KEY_PEM_PKCS5_UNENCRYPTED.replace(b"\n", b"\r\n")
         rv, = pem.parse(lf_pem)
 
         assert rv.as_bytes() == lf_pem

pip install -e .[dev]
parse_log_pytest
pytest
pytest
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
Automat==22.10.0
Babel==2.11.0
certifi==2021.5.30
cffi==1.15.1
cfgv==3.3.1
charset-normalizer==2.0.12
constantly==15.1.0
coverage==6.2
cryptography==40.0.2
distlib==0.3.9
docutils==0.18.1
filelock==3.4.1
hyperlink==21.0.0
identify==2.4.4
idna==3.10
imagesize==1.4.1
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
importlib-resources==5.2.3
incremental==22.10.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Jinja2==3.0.3
MarkupSafe==2.0.1
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
nodeenv==1.6.0
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
-e git+https://github.com/hynek/pem.git@9f3bc654d17503a18ace83329f4724a4c0271e10#egg=pem
platformdirs==2.4.0
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
pre-commit==2.17.0
pretend==1.0.9
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycparser==2.21
Pygments==2.14.0
pyOpenSSL==23.2.0
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
pytz==2025.2
PyYAML==6.0.1
requests==2.27.1
service-identity==21.1.0
six==1.17.0
snowballstemmer==2.2.0
Sphinx==5.3.0
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
Twisted==22.4.0
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
urllib3==1.26.20
virtualenv==20.16.2
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work
zope.interface==5.5.2

name: pem
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - automat==22.10.0
      - babel==2.11.0
      - cffi==1.15.1
      - cfgv==3.3.1
      - charset-normalizer==2.0.12
      - constantly==15.1.0
      - coverage==6.2
      - cryptography==40.0.2
      - distlib==0.3.9
      - docutils==0.18.1
      - filelock==3.4.1
      - hyperlink==21.0.0
      - identify==2.4.4
      - idna==3.10
      - imagesize==1.4.1
      - importlib-resources==5.2.3
      - incremental==22.10.0
      - jinja2==3.0.3
      - markupsafe==2.0.1
      - nodeenv==1.6.0
      - platformdirs==2.4.0
      - pre-commit==2.17.0
      - pretend==1.0.9
      - pyasn1==0.5.1
      - pyasn1-modules==0.3.0
      - pycparser==2.21
      - pygments==2.14.0
      - pyopenssl==23.2.0
      - pytz==2025.2
      - pyyaml==6.0.1
      - requests==2.27.1
      - service-identity==21.1.0
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==5.3.0
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - twisted==22.4.0
      - urllib3==1.26.20
      - virtualenv==20.16.2
      - zope-interface==5.5.2
prefix: /opt/conda/envs/pem

tests/test_core.py::TestParse::test_key_pkcs8_encrypted
tests/test_core.py::TestPEMObjects::test_cert_has_correct_repr tests/test_core.py::TestPEMObjects::test_cert_has_correct_str tests/test_core.py::TestPEMObjects::test_cert_req_has_correct_repr tests/test_core.py::TestPEMObjects::test_sha1_hexdigest tests/test_core.py::TestPEMObjects::test_as_text tests/test_core.py::TestPEMObjects::test_cert_req_has_correct_str tests/test_core.py::TestPEMObjects::test_key_has_correct_repr tests/test_core.py::TestPEMObjects::test_key_has_correct_str tests/test_core.py::TestPEMObjects::test_rsa_key_has_correct_repr tests/test_core.py::TestPEMObjects::test_rsa_key_has_correct_str tests/test_core.py::TestPEMObjects::test_dh_params_has_correct_repr tests/test_core.py::TestPEMObjects::test_dh_params_has_correct_str tests/test_core.py::TestPEMObjects::test_crl_has_correct_repr tests/test_core.py::TestPEMObjects::test_crl_has_correct_str tests/test_core.py::TestPEMObjects::test_certificate_unicode tests/test_core.py::TestPEMObjects::test_certificate_request_unicode tests/test_core.py::TestPEMObjects::test_key_unicode tests/test_core.py::TestPEMObjects::test_rsa_key_unicode tests/test_core.py::TestPEMObjects::test_dhparams_unicode_deprecated tests/test_core.py::TestPEMObjects::test_crl_unicode tests/test_core.py::TestPEMObjects::test_certs_equal tests/test_core.py::TestPEMObjects::test_cert_reqs_equal tests/test_core.py::TestPEMObjects::test_keys_equal tests/test_core.py::TestPEMObjects::test_rsa_keys_equal tests/test_core.py::TestPEMObjects::test_dh_params_equal tests/test_core.py::TestPEMObjects::test_crl_equal tests/test_core.py::TestPEMObjects::test_cert_contents_unequal tests/test_core.py::TestPEMObjects::test_cert_req_contents_unequal tests/test_core.py::TestPEMObjects::test_crl_unequal tests/test_core.py::TestPEMObjects::test_different_objects_unequal tests/test_core.py::TestPEMObjects::test_incompatible_types tests/test_core.py::TestParse::test_key_pkcs5_unencrypted tests/test_core.py::TestParse::test_key_pkcs5_encrypted tests/test_core.py::TestParse::test_key_pkcs8_unencrypted tests/test_core.py::TestParse::test_certificates tests/test_core.py::TestParse::test_certificate_no_new_line tests/test_core.py::TestParse::test_certificates_no_new_line tests/test_core.py::TestParse::test_dh tests/test_core.py::TestParse::test_crl tests/test_core.py::TestParse::test_file tests/test_core.py::TestParse::test_loads_certifi tests/test_core.py::TestParse::test_allows_lf
CHANGELOG.rst CONTRIBUTING.rst src/pem/_core.py setup.cfg
CHANGELOG.rst CONTRIBUTING.rst src/pem/_core.py setup.cfg