Ejemplo n.º 1
0
def wrap(private_key,
         key_oid,
         passphrase=None,
         protection=None,
         prot_params=None,
         key_params=None,
         randfunc=None):
    if key_params is None:
        key_params = DerNull()
    pk_info = newDerSequence(0, newDerSequence(DerObjectId(key_oid),
                                               key_params),
                             newDerOctetString(private_key))
    pk_info_der = pk_info.encode()
    if not passphrase:
        return pk_info_der
    else:
        passphrase = tobytes(passphrase)
        if protection is None:
            protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
        return PBES2.encrypt(pk_info_der, passphrase, protection, prot_params,
                             randfunc)
Ejemplo n.º 2
0
def wrap(private_key,
         key_oid,
         passphrase=None,
         protection=None,
         prot_params=None,
         key_params=None,
         randfunc=None):
    """Wrap a private key into a PKCS#8 blob (clear or encrypted).

    :Parameters:

      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 : (binary) 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 1 000.        |
        |                  | The default value for scrypt 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.                                   |
        +------------------+-----------------------------------------------+

      key_params : DER object
        The algorithm parameters associated to the private key.
        It is required for algorithms like DSA, but not for others like RSA.

      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 ``Crypto.Random``.

    :Return:
      The PKCS#8-wrapped private key (possibly encrypted),
      as a binary string.
    """

    if key_params is None:
        key_params = DerNull()

    #
    #   PrivateKeyInfo ::= SEQUENCE {
    #       version                 Version,
    #       privateKeyAlgorithm     PrivateKeyAlgorithmIdentifier,
    #       privateKey              PrivateKey,
    #       attributes              [0]  IMPLICIT Attributes OPTIONAL
    #   }
    #
    pk_info = DerSequence([
        0,
        DerSequence([DerObjectId(key_oid), key_params]),
        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)
Ejemplo n.º 3
0
    if passphrase:
        passphrase = tobytes(passphrase)

        found = False
        try:
            p8_private_key = PBES1.decrypt(p8_private_key, passphrase)
            found = True
        except PbesError, 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, 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))
    if len(pk_info) == 2 and not passphrase:
        raise ValueError("Not a valid clear PKCS#8 structure "
                         "(maybe it is encrypted?)")

    #
Ejemplo n.º 4
0
def unwrap(p8_private_key, passphrase=None):
    """Unwrap a private key from a PKCS#8 blob (clear or encrypted).

    :Parameters:
      p8_private_key : byte string
        The private key wrapped into a PKCS#8 blob, DER encoded.
      passphrase : (byte) 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))
    if len(pk_info) == 2 and not passphrase:
        raise ValueError("Not a valid clear PKCS#8 structure "
                         "(maybe it is encrypted?)")

    #
    #   PrivateKeyInfo ::= SEQUENCE {
    #       version                 Version,
    #       privateKeyAlgorithm     PrivateKeyAlgorithmIdentifier,
    #       privateKey              PrivateKey,
    #       attributes              [0]  IMPLICIT Attributes OPTIONAL
    #   }
    #   Version ::= INTEGER
    if pk_info[0] != 0:
        raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")

    # PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
    #
    #   EncryptedPrivateKeyInfo ::= SEQUENCE {
    #       encryptionAlgorithm  EncryptionAlgorithmIdentifier,
    #       encryptedData        EncryptedData
    #   }
    #   EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier

    #   AlgorithmIdentifier  ::=  SEQUENCE  {
    #       algorithm   OBJECT IDENTIFIER,
    #       parameters  ANY DEFINED BY algorithm OPTIONAL
    #   }

    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]

    #   EncryptedData ::= OCTET STRING
    private_key = DerOctetString().decode(pk_info[2]).payload

    return (algo_oid, private_key, algo_params)
Ejemplo n.º 5
0
def wrap(private_key, key_oid, passphrase=None, protection=None,
         prot_params=None, key_params=None, randfunc=None):
    """Wrap a private key into a PKCS#8 blob (clear or encrypted).

    :Parameters:

      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 : (binary) 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 1 000.        |
        |                  | The default value for scrypt 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.                                   |
        +------------------+-----------------------------------------------+

      key_params : DER object
        The algorithm parameters associated to the private key.
        It is required for algorithms like DSA, but not for others like RSA.

      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 ``Crypto.Random``.

    :Return:
      The PKCS#8-wrapped private key (possibly encrypted),
      as a binary string.
    """

    if key_params is None:
        key_params = DerNull()

    #
    #   PrivateKeyInfo ::= SEQUENCE {
    #       version                 Version,
    #       privateKeyAlgorithm     PrivateKeyAlgorithmIdentifier,
    #       privateKey              PrivateKey,
    #       attributes              [0]  IMPLICIT Attributes OPTIONAL
    #   }
    #
    pk_info = newDerSequence(
                0,
                newDerSequence(
                    DerObjectId(key_oid),
                    key_params
                ),
                newDerOctetString(private_key)
            )
    pk_info_der = pk_info.encode()

    if not passphrase:
        return pk_info_der

    # 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)
Ejemplo n.º 6
0
    if passphrase:
        passphrase = tobytes(passphrase)

        found = False
        try:
            p8_private_key = PBES1.decrypt(p8_private_key, passphrase)
            found = True
        except PbesError, 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, 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 = decode_der(DerSequence, p8_private_key)
    if len(pk_info) == 2 and not passphrase:
        raise ValueError("Not a valid clear PKCS#8 structure "
                         "(maybe it is encrypted?)")
    if not 3 <= len(pk_info) <= 4 or pk_info[0] != 0:
        raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
Ejemplo n.º 7
0
def unwrap(p8_private_key, passphrase=None):
    """Unwrap a private key from a PKCS#8 blob (clear or encrypted).

    :Parameters:
      p8_private_key : byte string
        The private key wrapped into a PKCS#8 blob, DER encoded.
      passphrase : (byte) 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 = decode_der(DerSequence, p8_private_key)
    if len(pk_info) == 2 and not passphrase:
        raise ValueError("Not a valid clear PKCS#8 structure "
                         "(maybe it is encrypted?)")
    if not 3 <= len(pk_info) <= 4 or pk_info[0] != 0:
        raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")

    #
    #   AlgorithmIdentifier  ::=  SEQUENCE  {
    #       algorithm               OBJECT IDENTIFIER,
    #       parameters              ANY DEFINED BY algorithm OPTIONAL
    #   }
    #
    algo_id = decode_der(DerSequence, pk_info[1])
    if not 1 <= len(algo_id) <= 2:
        raise ValueError("Not a valid AlgorithmIdentifier SEQUENCE")
    algo = decode_der(DerObjectId, algo_id[0]).value
    private_key = decode_der(DerOctetString, pk_info[2]).payload
    if len(algo_id) == 2 and algo_id[1] != b('\x05\x00'):
        params = algo_id[1]
    else:
        params = None
    return (algo, private_key, params)
Ejemplo n.º 8
0
def unwrap(p8_private_key, passphrase=None):
    """Unwrap a private key from a PKCS#8 blob (clear or encrypted).

    :Parameters:
      p8_private_key : byte string
        The private key wrapped into a PKCS#8 blob, DER encoded.
      passphrase : (byte) 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))
    if len(pk_info) == 2 and not passphrase:
        raise ValueError("Not a valid clear PKCS#8 structure "
                         "(maybe it is encrypted?)")

    #
    #   PrivateKeyInfo ::= SEQUENCE {
    #       version                 Version,
    #       privateKeyAlgorithm     PrivateKeyAlgorithmIdentifier,
    #       privateKey              PrivateKey,
    #       attributes              [0]  IMPLICIT Attributes OPTIONAL
    #   }
    #   Version ::= INTEGER
    if pk_info[0] != 0:
        raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")

    # PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
    #
    #   EncryptedPrivateKeyInfo ::= SEQUENCE {
    #       encryptionAlgorithm  EncryptionAlgorithmIdentifier,
    #       encryptedData        EncryptedData
    #   }
    #   EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier

    #   AlgorithmIdentifier  ::=  SEQUENCE  {
    #       algorithm   OBJECT IDENTIFIER,
    #       parameters  ANY DEFINED BY algorithm OPTIONAL
    #   }

    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]

    #   EncryptedData ::= OCTET STRING
    private_key = DerOctetString().decode(pk_info[2]).payload

    return (algo_oid, private_key, algo_params)
Ejemplo n.º 9
0
 def test6(self):
     ct = PBES2.encrypt(self.ref, self.passphrase,
                        'scryptAndAES256-CBC')
     pt = PBES2.decrypt(ct, self.passphrase)
     self.assertEqual(self.ref, pt)
Ejemplo n.º 10
0
 def test3(self):
     ct = PBES2.encrypt(self.ref, self.passphrase,
                        'PBKDF2WithHMAC-SHA1AndAES192-CBC')
     pt = PBES2.decrypt(ct, self.passphrase)
     self.assertEqual(self.ref, pt)
Ejemplo n.º 11
0
 def test6(self):
     ct = PBES2.encrypt(self.ref, self.passphrase,
                        'scryptAndAES256-CBC')
     pt = PBES2.decrypt(ct, self.passphrase)
     self.assertEqual(self.ref, pt)
Ejemplo n.º 12
0
 def test3(self):
     ct = PBES2.encrypt(self.ref, self.passphrase,
                        'PBKDF2WithHMAC-SHA1AndAES192-CBC')
     pt = PBES2.decrypt(ct, self.passphrase)
     self.assertEqual(self.ref, pt)
Ejemplo n.º 13
0
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)