From a14a22203fdf6f4b25c45d2ef94db0acba14ba51 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sun, 7 Jan 2024 11:15:44 +0100 Subject: [PATCH] Update the PKCS#8 documentation --- Doc/src/io/pkcs8.rst | 98 +++++++++++++++++++++++++++++++++++------- lib/Crypto/IO/PKCS8.py | 49 ++++++++------------- 2 files changed, 100 insertions(+), 47 deletions(-) diff --git a/Doc/src/io/pkcs8.rst b/Doc/src/io/pkcs8.rst index ed6212df5..8955cf913 100644 --- a/Doc/src/io/pkcs8.rst +++ b/Doc/src/io/pkcs8.rst @@ -1,28 +1,94 @@ PKCS#8 ====== -`PKCS#8`_ is a standard for storing and transferring private key information. -The wrapped key can either be clear or encrypted. +`PKCS#8`_ is a standard for encoding asymmetric private keys, +such as RSA or ECC, so that they can be stored or exchanged. +The private key can either be encrypted with a passphrase or +left in the clear. -All encryption algorithms are based on passphrase-based key derivation. -The following mechanisms are fully supported: +Example of how to encrypt an ECC private key (even though +normally you would use the ``export_key`` method of the key itself):: -* *PBKDF2WithHMAC-SHA1AndAES128-CBC* -* *PBKDF2WithHMAC-SHA1AndAES192-CBC* -* *PBKDF2WithHMAC-SHA1AndAES256-CBC* -* *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* -* *scryptAndAES128-CBC* -* *scryptAndAES192-CBC* -* *scryptAndAES256-CBC* + from Crypto.PublicKey import ECC + from Crypto.IO import PKCS8 -The following mechanisms are only supported for importing keys. + key = ECC.generate(curve='p256') + pkey = key.export_key(format='DER'), + passphrase = b'secret santa' + encrypted_key = PKCS8.wrap( + pkey, + "1.2.840.10045.2.1", # unrestricted ECC + passphrase=passphrase, + protection='PBKDF2WithHMAC-SHA512AndAES256-CBC', + prot_params={'iteration_count': 210000} + ) + +.. _enc_params: + +Encryption parameters +----------------------- + +When creating an encrypted PKCS#8 container, the two parameters +``protection`` and ``prot_params`` drive the encryption algorithm: + +* ``protection`` (mandatory), a string that defines how the encryption + key is derived from the passphrase, and which cipher to use. + The string must follow one of the two patterns: + + #. ``'PBKDF2WithHMAC-'`` + **hash** + ``'And'`` + **cipher** + #. ``'scryptAnd'`` + **cipher** + + where **hash** is the name of the cryptographic hash + (recommended: ``'SHA512'``) and **cipher** is the name + of the cipher mode to use (recommended: ``'AES256-CBC'``). + + Other values for **hash** are ``'SHA1'``, ``'SHA224'``, ``'SHA256'``, + ``'SHA384'``, ``'SHA512-224'``, ``'SHA512-256'``, ``'SHA3-224'``, + ``'SHA3-256'``, ``'SHA3-384'``, ``'SHA3-512'``. + + Other values for **cipher** are + ``'AES128-GCM'``, ``'AES192-GCM'``, ``'AES256-GCM'``, + ``'AES128-CBC'``, ``'AES192-CBC'`` or ``'DES-EDE3-CBC'``. + +* ``prot_params`` (optional), a dictionary to override the parameters of the + key derivation function: + + +------------------+-----------------------------------------------+ + | 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). | + | | | + | | **For PBKDF2 with SHA512 the recommended | + | | value is 210 000** (default is 1 000). | + | | | + | | **For scrypt the recommended value is | + | | 131 072** (default value is 16 384). | + +------------------+-----------------------------------------------+ + | 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. | + +------------------+-----------------------------------------------+ + + +Legacy algorithms +----------------- + +The following ``protection`` mechanisms are only supported for importing keys. They are much weaker than the ones listed above, and they are provided for backward compatibility only: -* *pbeWithMD5AndRC2-CBC* -* *pbeWithMD5AndDES-CBC* -* *pbeWithSHA1AndRC2-CBC* -* *pbeWithSHA1AndDES-CBC* +* ``pbeWithMD5AndRC2-CBC`` +* ``pbeWithMD5AndDES-CBC`` +* ``pbeWithSHA1AndRC2-CBC`` +* ``pbeWithSHA1AndDES-CBC`` .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt diff --git a/lib/Crypto/IO/PKCS8.py b/lib/Crypto/IO/PKCS8.py index 18dffae35..0747dfc1d 100644 --- a/lib/Crypto/IO/PKCS8.py +++ b/lib/Crypto/IO/PKCS8.py @@ -53,44 +53,29 @@ def wrap(private_key, key_oid, passphrase=None, protection=None, Args: - private_key (byte string): + private_key (bytes): 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). + It is a dotted string, like ``'1.2.840.113549.1.1.1'`` (for RSA keys) + or ``'1.2.840.10045.2.1'`` (for ECC keys). - passphrase (bytes string or string): + Keyword Args: + + passphrase (bytes 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``. + Refer to :ref:`the encryption parameters` . + 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. | - +------------------+-----------------------------------------------+ + Parameters for the key derivation function (KDF). + Refer to :ref:`the encryption parameters` . key_params (DER object or None): The ``parameters`` field to use in the ``AlgorithmIdentifier`` @@ -103,8 +88,8 @@ def wrap(private_key, key_oid, passphrase=None, protection=None, 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. + Returns: + bytes: The PKCS#8-wrapped private key (possibly encrypted). """ # @@ -145,8 +130,10 @@ 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. + p8_private_key (bytes): + The private key wrapped into a PKCS#8 container, DER encoded. + + Keyword Args: passphrase (byte string or string): The passphrase to use to decrypt the blob (if it is encrypted). @@ -154,8 +141,8 @@ def unwrap(p8_private_key, passphrase=None): 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`` + #. the private key (bytes, DER encoded) + #. the associated parameters (bytes, DER encoded) or ``None`` Raises: ValueError : if decoding fails