summaryrefslogtreecommitdiffstats
path: root/lib/Crypto/IO/PKCS8.py
diff options
context:
space:
mode:
authorxiubuzhe <xiubuzhe@sina.com>2023-10-08 20:59:00 +0800
committerxiubuzhe <xiubuzhe@sina.com>2023-10-08 20:59:00 +0800
commit1dac2263372df2b85db5d029a45721fa158a5c9d (patch)
tree0365f9c57df04178a726d7584ca6a6b955a7ce6a /lib/Crypto/IO/PKCS8.py
parentb494be364bb39e1de128ada7dc576a729d99907e (diff)
downloadsunhpc-1dac2263372df2b85db5d029a45721fa158a5c9d.tar.gz
sunhpc-1dac2263372df2b85db5d029a45721fa158a5c9d.tar.bz2
sunhpc-1dac2263372df2b85db5d029a45721fa158a5c9d.zip
first add files
Diffstat (limited to 'lib/Crypto/IO/PKCS8.py')
-rw-r--r--lib/Crypto/IO/PKCS8.py239
1 files changed, 239 insertions, 0 deletions
diff --git a/lib/Crypto/IO/PKCS8.py b/lib/Crypto/IO/PKCS8.py
new file mode 100644
index 0000000..18dffae
--- /dev/null
+++ b/lib/Crypto/IO/PKCS8.py
@@ -0,0 +1,239 @@
+#
+# PublicKey/PKCS8.py : PKCS#8 functions
+#
+# ===================================================================
+#
+# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# ===================================================================
+
+
+from Crypto.Util.py3compat import *
+
+from Crypto.Util.asn1 import (
+ DerNull,
+ DerSequence,
+ DerObjectId,
+ DerOctetString,
+ )
+
+from Crypto.IO._PBES import PBES1, PBES2, PbesError
+
+
+__all__ = ['wrap', 'unwrap']
+
+
+def wrap(private_key, key_oid, passphrase=None, protection=None,
+ prot_params=None, key_params=DerNull(), randfunc=None):
+ """Wrap a private key into a PKCS#8 blob (clear or encrypted).
+
+ Args:
+
+ private_key (byte string):
+ The private key encoded in binary form. The actual encoding is
+ algorithm specific. In most cases, it is DER.
+
+ key_oid (string):
+ The object identifier (OID) of the private key to wrap.
+ It is a dotted string, like ``1.2.840.113549.1.1.1`` (for RSA keys).
+
+ passphrase (bytes string or string):
+ The secret passphrase from which the wrapping key is derived.
+ Set it only if encryption is required.
+
+ protection (string):
+ The identifier of the algorithm to use for securely wrapping the key.
+ The default value is ``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``.
+
+ prot_params (dictionary):
+ Parameters for the protection algorithm.
+
+ +------------------+-----------------------------------------------+
+ | Key | Description |
+ +==================+===============================================+
+ | iteration_count | The KDF algorithm is repeated several times to|
+ | | slow down brute force attacks on passwords |
+ | | (called *N* or CPU/memory cost in scrypt). |
+ | | The default value for PBKDF2 is 1000. |
+ | | The default value for scrypt is 16384. |
+ +------------------+-----------------------------------------------+
+ | salt_size | Salt is used to thwart dictionary and rainbow |
+ | | attacks on passwords. The default value is 8 |
+ | | bytes. |
+ +------------------+-----------------------------------------------+
+ | block_size | *(scrypt only)* Memory-cost (r). The default |
+ | | value is 8. |
+ +------------------+-----------------------------------------------+
+ | parallelization | *(scrypt only)* CPU-cost (p). The default |
+ | | value is 1. |
+ +------------------+-----------------------------------------------+
+
+ key_params (DER object or None):
+ The ``parameters`` field to use in the ``AlgorithmIdentifier``
+ SEQUENCE. If ``None``, no ``parameters`` field will be added.
+ By default, the ASN.1 type ``NULL`` is used.
+
+ randfunc (callable):
+ Random number generation function; it should accept a single integer
+ N and return a string of random data, N bytes long.
+ If not specified, a new RNG will be instantiated
+ from :mod:`Crypto.Random`.
+
+ Return:
+ The PKCS#8-wrapped private key (possibly encrypted), as a byte string.
+ """
+
+ #
+ # PrivateKeyInfo ::= SEQUENCE {
+ # version Version,
+ # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ # privateKey PrivateKey,
+ # attributes [0] IMPLICIT Attributes OPTIONAL
+ # }
+ #
+ if key_params is None:
+ algorithm = DerSequence([DerObjectId(key_oid)])
+ else:
+ algorithm = DerSequence([DerObjectId(key_oid), key_params])
+
+ pk_info = DerSequence([
+ 0,
+ algorithm,
+ DerOctetString(private_key)
+ ])
+ pk_info_der = pk_info.encode()
+
+ if passphrase is None:
+ return pk_info_der
+
+ if not passphrase:
+ raise ValueError("Empty passphrase")
+
+ # Encryption with PBES2
+ passphrase = tobytes(passphrase)
+ if protection is None:
+ protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
+ return PBES2.encrypt(pk_info_der, passphrase,
+ protection, prot_params, randfunc)
+
+
+def unwrap(p8_private_key, passphrase=None):
+ """Unwrap a private key from a PKCS#8 blob (clear or encrypted).
+
+ Args:
+ p8_private_key (byte string):
+ The private key wrapped into a PKCS#8 blob, DER encoded.
+ passphrase (byte string or string):
+ The passphrase to use to decrypt the blob (if it is encrypted).
+
+ Return:
+ A tuple containing
+
+ #. the algorithm identifier of the wrapped key (OID, dotted string)
+ #. the private key (byte string, DER encoded)
+ #. the associated parameters (byte string, DER encoded) or ``None``
+
+ Raises:
+ ValueError : if decoding fails
+ """
+
+ if passphrase:
+ passphrase = tobytes(passphrase)
+
+ found = False
+ try:
+ p8_private_key = PBES1.decrypt(p8_private_key, passphrase)
+ found = True
+ except PbesError as e:
+ error_str = "PBES1[%s]" % str(e)
+ except ValueError:
+ error_str = "PBES1[Invalid]"
+
+ if not found:
+ try:
+ p8_private_key = PBES2.decrypt(p8_private_key, passphrase)
+ found = True
+ except PbesError as e:
+ error_str += ",PBES2[%s]" % str(e)
+ except ValueError:
+ error_str += ",PBES2[Invalid]"
+
+ if not found:
+ raise ValueError("Error decoding PKCS#8 (%s)" % error_str)
+
+ pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4, 5))
+ if len(pk_info) == 2 and not passphrase:
+ raise ValueError("Not a valid clear PKCS#8 structure "
+ "(maybe it is encrypted?)")
+
+ # RFC5208, PKCS#8, version is v1(0)
+ #
+ # PrivateKeyInfo ::= SEQUENCE {
+ # version Version,
+ # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ # privateKey PrivateKey,
+ # attributes [0] IMPLICIT Attributes OPTIONAL
+ # }
+ #
+ # RFC5915, Asymmetric Key Package, version is v2(1)
+ #
+ # OneAsymmetricKey ::= SEQUENCE {
+ # version Version,
+ # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ # privateKey PrivateKey,
+ # attributes [0] Attributes OPTIONAL,
+ # ...,
+ # [[2: publicKey [1] PublicKey OPTIONAL ]],
+ # ...
+ # }
+
+ if pk_info[0] == 0:
+ if len(pk_info) not in (3, 4):
+ raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
+ elif pk_info[0] == 1:
+ if len(pk_info) not in (3, 4, 5):
+ raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
+ else:
+ raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
+
+ algo = DerSequence().decode(pk_info[1], nr_elements=(1, 2))
+ algo_oid = DerObjectId().decode(algo[0]).value
+ if len(algo) == 1:
+ algo_params = None
+ else:
+ try:
+ DerNull().decode(algo[1])
+ algo_params = None
+ except:
+ algo_params = algo[1]
+
+ # PrivateKey ::= OCTET STRING
+ private_key = DerOctetString().decode(pk_info[2]).payload
+
+ # We ignore attributes and (for v2 only) publickey
+
+ return (algo_oid, private_key, algo_params)