def finalize_padded(self, pkey):
     if pkey.key_type not in (HAL_KEY_TYPE_RSA_PRIVATE, HAL_KEY_TYPE_RSA_PUBLIC):
         return self.finalize()
     # PKCS #1.5 requires the digest to be wrapped up in an ASN.1 DigestInfo object.
     from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
     return DerSequence([DerSequence([self._context.oid, DerNull().encode()]).encode(),
                         DerOctetString(self.finalize()).encode()]).encode()
Exemple #2
0
def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
    """
    Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined
    in PKCS#1 v2.1 (RFC3447, 9.2).

    ``EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input,
    and hash it internally. Here, we expect that the message has already
    been hashed instead.

    :Parameters:
     hash : hash object
            The hash object that holds the digest of the message being signed.
     emLen : int
            The length the final encoding must have, in bytes.

    :attention: the early standard (RFC2313) stated that ``DigestInfo``
        had to be BER-encoded. This means that old signatures
        might have length tags in indefinite form, which
        is not supported in DER. Such encoding cannot be
        reproduced by this function.

    :attention: the same standard defined ``DigestAlgorithm`` to be
        of ``AlgorithmIdentifier`` type, where the PARAMETERS
        item is optional. Encodings for ``MD2/4/5`` without
        ``PARAMETERS`` cannot be reproduced by this function.

    :Return: An ``emLen`` byte long string that encodes the hash.
    """

    # First, build the ASN.1 DER object DigestInfo:
    #
    #   DigestInfo ::= SEQUENCE {
    #       digestAlgorithm AlgorithmIdentifier,
    #       digest OCTET STRING
    #   }
    #
    # where digestAlgorithm identifies the hash function and shall be an
    # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms.
    #
    #   PKCS1-v1-5DigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
    #       { OID id-md2 PARAMETERS NULL    }|
    #       { OID id-md5 PARAMETERS NULL    }|
    #       { OID id-sha1 PARAMETERS NULL   }|
    #       { OID id-sha256 PARAMETERS NULL }|
    #       { OID id-sha384 PARAMETERS NULL }|
    #       { OID id-sha512 PARAMETERS NULL }
    #   }
    #
    digestAlgo = DerSequence([hash.oid, DerNull().encode()])
    digest = DerOctetString(hash.digest())
    digestInfo = DerSequence([digestAlgo.encode(), digest.encode()]).encode()

    # We need at least 11 bytes for the remaining data: 3 fixed bytes and
    # at least 8 bytes of padding).
    if emLen < len(digestInfo) + 11:
        raise ValueError(
            "Selected hash algorith has a too long digest (%d bytes)." %
            len(digest))
    PS = bchr(0xFF) * (emLen - len(digestInfo) - 3)
    return b("\x00\x01") + PS + bchr(0x00) + digestInfo
Exemple #3
0
def _create_subject_public_key_info(algo_oid, secret_key, params=None):

    if params is None:
        params = DerNull()

    spki = DerSequence([
        DerSequence([DerObjectId(algo_oid), params]),
        DerBitString(secret_key)
    ])
    return spki.encode()
Exemple #4
0
 def _encode(self, message):
     hash_oid = self.hash_function.get_OID()
     digest = self.hash_function.hash(message)
     der_digest = DerOctetString(digest).encode()
     der_null = DerNull().encode()
     der_sequence = DerSequence([hash_oid, der_null]).encode()
     hash_info = DerSequence([der_sequence, der_digest]).encode()
     hash_size = len(hash_info)
     padding = '\xff'*(self.n_size - hash_size - 3)
     return '\x00\x01' + padding + '\0' + hash_info
Exemple #5
0
    def test4(self):
        """Verify wrapping with encryption"""

        for t in self.wrapped_enc_keys:
            if t[0] == 'skip encryption':
                continue
            rng = Rng(t[2] + t[3])
            params = {'iteration_count': t[1]}
            wrapped = PKCS8.wrap(self.clear_key,
                                 self.oid_key,
                                 b("TestTest"),
                                 protection=t[0],
                                 prot_params=params,
                                 key_params=DerNull(),
                                 randfunc=rng)
            self.assertEqual(wrapped, t[4])
Exemple #6
0
def pkcs1_v1_5_encode(msg_hash: SHA256.SHA256Hash, emLen: int) -> bytes:
    # this code is copied from  EMSA_PKCS1_V1_5_ENCODE
    # https://github.com/dlitz/pycrypto/blob/v2.7a1/lib/Crypto/Signature/PKCS1_v1_5.py#L173
    digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ])

    #if with_hash_parameters:
    if True:
        digestAlgo.append(DerNull().encode())

    digest      = DerOctetString(msg_hash.digest())
    digestInfo  = DerSequence([
                    digestAlgo.encode(),
                      digest.encode()
                    ]).encode()

    # We need at least 11 bytes for the remaining data: 3 fixed bytes and
    # at least 8 bytes of padding).
    if emLen<len(digestInfo)+11:
          raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest))
    PS = b'\xFF' * (emLen - len(digestInfo) - 3)
    return b'\x00\x01' + PS + b'\x00' + digestInfo
Exemple #7
0
        def CRYPTO_EMSA_PKCS1_V1_5_ENCODE(M, emLen):
            msg_hash = SHA256.new(M)
            digestAlgo = DerSequence([DerObjectId(msg_hash.oid).encode()])
            print(digestAlgo)

            digestAlgo.append(DerNull().encode())

            digest = DerOctetString(msg_hash.digest())
            digestInfo = DerSequence([digestAlgo.encode(),
                                      digest.encode()]).encode()
            print("%x" % int.from_bytes(digestInfo, byteorder='big'))
            print("%x" % int.from_bytes(digestAlgo.encode(), byteorder='big'))
            print("%x" % int.from_bytes(digest.encode(), byteorder='big'))
            print("%x" % int.from_bytes(msg_hash.digest(), byteorder='big'))

            #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 2004 00 0501020403650148866009060d30 3130
            #                                                                          501020403650148866009060d30
            #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273 2004
            #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc132273
            #b91d0b7a09f57c109926a449647283adb5dc213c0fdb0cf2b219e064cc1322732004000501020403650148866009060d30313000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0100

            #3031 300d06096086480165030402010500 0420 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9
            #     300d06096086480165030402010500
            #                                    0420 732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9
            #                                         732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9
            #0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420732213cc64e019b2f20cdb0f3c21dcb5ad83726449a42699107cf5097a0b1db9

            # We need at least 11 bytes for the remaining data: 3 fixed bytes and
            # at least 8 bytes of padding).
            if emLen < len(digestInfo) + 11:
                raise TypeError(
                    "Selected hash algorith has a too long digest (%d bytes)."
                    % len(digest))
            PS = b'\xFF' * (emLen - len(digestInfo) - 3)
            out = b'\x00\x01' + PS + b'\x00' + digestInfo
            print("%x" % int.from_bytes(out, byteorder='big'))
            return out
Exemple #8
0
def _expand_subject_public_key_info(encoded):
    """Parse a SubjectPublicKeyInfo structure.

    It returns a triple with:
        * OID (string)
        * encoded public key (bytes)
        * Algorithm parameters (bytes or None)
    """

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

    spki = DerSequence().decode(encoded, nr_elements=2)
    algo = DerSequence().decode(spki[0], nr_elements=(1, 2))
    algo_oid = DerObjectId().decode(algo[0])
    spk = DerBitString().decode(spki[1]).value

    if len(algo) == 1:
        algo_params = None
    else:
        try:
            DerNull().decode(algo[1])
            algo_params = None
        except:
            algo_params = algo[1]

    return algo_oid.value, spk, algo_params
Exemple #9
0
 def testDecode1(self):
     # Empty sequence
     der = DerNull()
     self.assertEquals(der, der.decode(b('\x05\x00')))
Exemple #10
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)
Exemple #11
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)
Exemple #12
0
 def testEncode1(self):
     der = DerNull()
     self.assertEquals(der.encode(), b('\x05\x00'))
Exemple #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)
Exemple #14
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)
Exemple #15
0
 def testDecode1(self):
     # Empty sequence
     der = DerNull()
     self.assertEqual(der, der.decode(b('\x05\x00')))
Exemple #16
0
def _EMSA_PKCS1_V1_5_ENCODE(msg_hash, emLen, with_hash_parameters=True):
    """
    Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined
    in PKCS#1 v2.1 (RFC3447, 9.2).

    ``_EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input,
    and hash it internally. Here, we expect that the message has already
    been hashed instead.

    :Parameters:
     msg_hash : hash object
            The hash object that holds the digest of the message being signed.
     emLen : int
            The length the final encoding must have, in bytes.
     with_hash_parameters : bool
            If True (default), include NULL parameters for the hash
            algorithm in the ``digestAlgorithm`` SEQUENCE.

    :attention: the early standard (RFC2313) stated that ``DigestInfo``
        had to be BER-encoded. This means that old signatures
        might have length tags in indefinite form, which
        is not supported in DER. Such encoding cannot be
        reproduced by this function.

    :Return: An ``emLen`` byte long string that encodes the hash.
    """

    # First, build the ASN.1 DER object DigestInfo:
    #
    #   DigestInfo ::= SEQUENCE {
    #       digestAlgorithm AlgorithmIdentifier,
    #       digest OCTET STRING
    #   }
    #
    # where digestAlgorithm identifies the hash function and shall be an
    # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms.
    #
    #   PKCS1-v1-5DigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
    #       { OID id-md2 PARAMETERS NULL    }|
    #       { OID id-md5 PARAMETERS NULL    }|
    #       { OID id-sha1 PARAMETERS NULL   }|
    #       { OID id-sha256 PARAMETERS NULL }|
    #       { OID id-sha384 PARAMETERS NULL }|
    #       { OID id-sha512 PARAMETERS NULL }
    #   }
    #
    # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters
    # should be omitted. They may be present, but when they are, they shall
    # have NULL value.

    digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ])

    if with_hash_parameters:
        digestAlgo.append(DerNull().encode())

    digest      = DerOctetString(msg_hash.digest())
    digestInfo  = DerSequence([
                    digestAlgo.encode(),
                    digest.encode()
                    ]).encode()

    # We need at least 11 bytes for the remaining data: 3 fixed bytes and
    # at least 8 bytes of padding).
    if emLen<len(digestInfo)+11:
        raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest))
    PS = b'\xFF' * (emLen - len(digestInfo) - 3)
    return b'\x00\x01' + PS + b'\x00' + digestInfo
Exemple #17
0
 def testEncode1(self):
     der = DerNull()
     self.assertEqual(der.encode(), b('\x05\x00'))
Exemple #18
0
 def testDecode1(self):
     # Empty sequence
     der = DerNull()
     der.decode(b('\x05\x00'))
Exemple #19
0
            # This is probably an OpenSSH key
            keystring = binascii.a2b_base64(extern_key.split(b(' '))[1])
            keyparts = []
            while len(keystring) > 4:
                l = struct.unpack(">I", keystring[:4])[0]
                keyparts.append(keystring[4:4 + l])
                keystring = keystring[4 + l:]
            e = Integer.from_bytes(keyparts[1])
            n = Integer.from_bytes(keyparts[2])
            return construct([n, e])

    if bord(extern_key[0]) == 0x30:
            # This is probably a DER encoded key
            return _importKeyDER(extern_key, passphrase)

    raise ValueError("RSA key format is not supported")

#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates
#: a generic RSA key, even when such key will be actually used for digital
#: signatures.
#:
#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html
oid = "1.2.840.113549.1.1.1"

#: This is the standard DER object that qualifies a cryptographic algorithm
#: in ASN.1-based data structures (e.g. X.509 certificates).
algorithmIdentifier = DerSequence(
  [DerObjectId(oid).encode(),      # algorithm field
  DerNull().encode()]              # parameters field
  ).encode()
Exemple #20
0
 def testDecode1(self):
     # Empty sequence
     der = DerNull()
     der.decode(b('\x05\x00'))
Exemple #21
0
def pkcs1_hash_and_pad(text):
    return DerSequence([
        DerSequence([SHA256.oid, DerNull().encode()]).encode(),
        DerOctetString(SHA256(text).digest()).encode()
    ]).encode()
Exemple #22
0
                # This is probably a DER encoded key
                return self._importKeyDER(externKey)
        
        raise ValueError("RSA key format is not supported")

#: This is the ASN.1 DER object that qualifies an algorithm as
#: compliant to PKCS#1 (that is, the standard RSA).
# It is found in all 'algorithm' fields (also called 'algorithmIdentifier').
# It is a SEQUENCE with the oid assigned to RSA and with its parameters (none).
#   0x06 0x09   OBJECT IDENTIFIER, 9 bytes of payload
#     0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x01 0x01
#               rsaEncryption (1 2 840 113549 1 1 1) (PKCS #1)
#   0x05 0x00   NULL
algorithmIdentifier = DerSequence(
  [ b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'),
  DerNull().encode() ]
  ).encode()
 
_impl = RSAImplementation()
#:
#: Randomly generate a fresh, new RSA key object.
#:
#: See `RSAImplementation.generate`.
#:
generate = _impl.generate
#:
#: Construct an RSA key object from a tuple of valid RSA components.
#:
#: See `RSAImplementation.construct`.
#:
construct = _impl.construct
Exemple #23
0
    def export_key(self,
                   format='PEM',
                   passphrase=None,
                   pkcs=1,
                   protection=None,
                   randfunc=None):
        """Export this RSA key.

        Args:
          format (string):
            The format to use for wrapping the key:

            - *'PEM'*. (*Default*) Text encoding, done according to `RFC1421`_/`RFC1423`_.
            - *'DER'*. Binary encoding.
            - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification.
              Only suitable for public keys (not private keys).

          passphrase (string):
            (*For private keys only*) The pass phrase used for protecting the output.

          pkcs (integer):
            (*For private keys only*) The ASN.1 structure to use for
            serializing the key. Note that even in case of PEM
            encoding, there is an inner ASN.1 DER structure.

            With ``pkcs=1`` (*default*), the private key is encoded in a
            simple `PKCS#1`_ structure (``RSAPrivateKey``).

            With ``pkcs=8``, the private key is encoded in a `PKCS#8`_ structure
            (``PrivateKeyInfo``).

            .. note::
                This parameter is ignored for a public key.
                For DER and PEM, an ASN.1 DER ``SubjectPublicKeyInfo``
                structure is always used.

          protection (string):
            (*For private keys only*)
            The encryption scheme to use for protecting the private key.

            If ``None`` (default), the behavior depends on :attr:`format`:

            - For *'DER'*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*
              scheme is used. The following operations are performed:

                1. A 16 byte Triple DES key is derived from the passphrase
                   using :func:`Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt,
                   and 1 000 iterations of :mod:`Crypto.Hash.HMAC`.
                2. The private key is encrypted using CBC.
                3. The encrypted key is encoded according to PKCS#8.

            - For *'PEM'*, the obsolete PEM encryption scheme is used.
              It is based on MD5 for key derivation, and Triple DES for encryption.

            Specifying a value for :attr:`protection` is only meaningful for PKCS#8
            (that is, ``pkcs=8``) and only if a pass phrase is present too.

            The supported schemes for PKCS#8 are listed in the
            :mod:`Crypto.IO.PKCS8` module (see :attr:`wrap_algo` parameter).

          randfunc (callable):
            A function that provides random bytes. Only used for PEM encoding.
            The default is :func:`Crypto.Random.get_random_bytes`.

        Returns:
          byte string: the encoded key

        Raises:
          ValueError:when the format is unknown or when you try to encrypt a private
            key with *DER* format and PKCS#1.

        .. warning::
            If you don't provide a pass phrase, the private key will be
            exported in the clear!

        .. _RFC1421:    http://www.ietf.org/rfc/rfc1421.txt
        .. _RFC1423:    http://www.ietf.org/rfc/rfc1423.txt
        .. _`PKCS#1`:   http://www.ietf.org/rfc/rfc3447.txt
        .. _`PKCS#8`:   http://www.ietf.org/rfc/rfc5208.txt
        """

        if passphrase is not None:
            passphrase = tobytes(passphrase)

        if randfunc is None:
            randfunc = Random.get_random_bytes

        if format == 'OpenSSH':
            e_bytes, n_bytes = [x.to_bytes() for x in (self._e, self._n)]
            if bord(e_bytes[0]) & 0x80:
                e_bytes = b'\x00' + e_bytes
            if bord(n_bytes[0]) & 0x80:
                n_bytes = b'\x00' + n_bytes
            keyparts = [b'ssh-rsa', e_bytes, n_bytes]
            keystring = b''.join(
                [struct.pack(">I", len(kp)) + kp for kp in keyparts])
            return b'ssh-rsa ' + binascii.b2a_base64(keystring)[:-1]

        # DER format is always used, even in case of PEM, which simply
        # encodes it into BASE64.
        if self.has_private():
            binary_key = DerSequence([
                0, self.n, self.e, self.d, self.p, self.q,
                self.d % (self.p - 1), self.d % (self.q - 1),
                Integer(self.q).inverse(self.p)
            ]).encode()
            if pkcs == 1:
                key_type = 'RSA PRIVATE KEY'
                if format == 'DER' and passphrase:
                    raise ValueError("PKCS#1 private key cannot be encrypted")
            else:  # PKCS#8
                from Crypto.IO import PKCS8

                if format == 'PEM' and protection is None:
                    key_type = 'PRIVATE KEY'
                    binary_key = PKCS8.wrap(binary_key,
                                            oid,
                                            None,
                                            key_params=DerNull())
                else:
                    key_type = 'ENCRYPTED PRIVATE KEY'
                    if not protection:
                        protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
                    binary_key = PKCS8.wrap(binary_key,
                                            oid,
                                            passphrase,
                                            protection,
                                            key_params=DerNull())
                    passphrase = None
        else:
            key_type = "PUBLIC KEY"
            binary_key = _create_subject_public_key_info(
                oid, DerSequence([self.n, self.e]), DerNull())

        if format == 'DER':
            return binary_key
        if format == 'PEM':
            from Crypto.IO import PEM

            pem_str = PEM.encode(binary_key, key_type, passphrase, randfunc)
            return tobytes(pem_str)

        raise ValueError(
            "Unknown key format '%s'. Cannot export the RSA key." % format)