def new(cls, alias, certs, key, key_format='pkcs8'): """ Helper function to create a new PrivateKeyEntry. :param str alias: The alias for the Private Key Entry :param list certs: An list of certificates, as byte strings. The first one should be the one belonging to the private key, the others the chain (in correct order). :param str key: A byte string containing the private key in the format specified in the key_format parameter (default pkcs8). :param str key_format: The format of the provided private key. Valid options are pkcs8 or rsa_raw. Defaults to pkcs8. :returns: A loaded :class:`PrivateKeyEntry` instance, ready to be placed in a keystore. :raises UnsupportedKeyFormatException: If the key format is unsupported. """ timestamp = int(time.time()) * 1000 cert_chain = [] for cert in certs: cert_chain.append(('X.509', cert)) pke = cls( timestamp=timestamp, # Alias must be lower case or it will corrupt the keystore for Java Keytool and Keytool Explorer alias=alias.lower(), cert_chain=cert_chain) if key_format == 'pkcs8': private_key_info = decoder.decode( key, asn1Spec=rfc5208.PrivateKeyInfo())[0] pke._algorithm_oid = private_key_info['privateKeyAlgorithm'][ 'algorithm'].asTuple() pke.pkey = private_key_info['privateKey'].asOctets() pke.pkey_pkcs8 = key elif key_format == 'rsa_raw': pke._algorithm_oid = RSA_ENCRYPTION_OID # We must encode it to pkcs8 private_key_info = rfc5208.PrivateKeyInfo() private_key_info.setComponentByName('version', 'v1') a = AlgorithmIdentifier() a.setComponentByName('algorithm', pke._algorithm_oid) a.setComponentByName('parameters', '\x05\x00') private_key_info.setComponentByName('privateKeyAlgorithm', a) private_key_info.setComponentByName('privateKey', key) pke.pkey_pkcs8 = encoder.encode(private_key_info, ifNotEmpty=True) pke.pkey = key else: raise UnsupportedKeyFormatException( "Key Format '%s' is not supported" % key_format) return pke
def decrypt(self, key_password): """ Decrypts the entry using the given password. Has no effect if the entry has already been decrypted. :param str key_password: The password to decrypt the entry with. If the entry was loaded from a JCEKS keystore, the password must not contain any characters outside of the ASCII character set. :raises DecryptionFailureException: If the entry could not be decrypted using the given password. :raises UnexpectedAlgorithmException: If the entry was encrypted with an unknown or unexpected algorithm :raise ValueError: If the entry was loaded from a JCEKS keystore and the password contains non-ASCII characters. """ if self.is_decrypted(): return encrypted_info = decoder.decode( self._encrypted, asn1Spec=rfc5208.EncryptedPrivateKeyInfo())[0] algo_id = encrypted_info['encryptionAlgorithm']['algorithm'].asTuple() algo_params = encrypted_info['encryptionAlgorithm'][ 'parameters'].asOctets() encrypted_private_key = encrypted_info['encryptedData'].asOctets() plaintext = None try: if algo_id == sun_crypto.SUN_JKS_ALGO_ID: plaintext = sun_crypto.jks_pkey_decrypt( encrypted_private_key, key_password) elif algo_id == sun_crypto.SUN_JCE_ALGO_ID: if self.store_type != "jceks": raise UnexpectedAlgorithmException( "Encountered JCEKS private key protection algorithm in JKS keystore" ) # see RFC 2898, section A.3: PBES1 and definitions of AlgorithmIdentifier and PBEParameter params = decoder.decode(algo_params, asn1Spec=rfc2898.PBEParameter())[0] salt = params['salt'].asOctets() iteration_count = int(params['iterationCount']) plaintext = sun_crypto.jce_pbe_decrypt(encrypted_private_key, key_password, salt, iteration_count) else: raise UnexpectedAlgorithmException( "Unknown %s private key protection algorithm: %s" % (self.store_type.upper(), algo_id)) except (BadHashCheckException, BadPaddingException): raise DecryptionFailureException( "Failed to decrypt data for private key '%s'; wrong password?" % self.alias) # at this point, 'plaintext' is a PKCS#8 PrivateKeyInfo (see RFC 5208) private_key_info = decoder.decode(plaintext, asn1Spec=rfc5208.PrivateKeyInfo())[0] key = private_key_info['privateKey'].asOctets() algorithm_oid = private_key_info['privateKeyAlgorithm'][ 'algorithm'].asTuple() self._encrypted = None self._pkey = key self._pkey_pkcs8 = plaintext self._algorithm_oid = algorithm_oid
def test_asn1_from_ed25519_private_key(self): priv = xtt.ED25519PrivateKey( b"""\xd1%\xce\xec\xfb\xdf\x82\xb1w~\xb5AL*\x10'\x9aX\x8f\xae\x05\tTm5\xafC\x14\x06]\xb3X^\x970Y=\\\x92\xbdsK2\x0cD%\x96\xf8\x1dh\xc4\x1d&k'+\x1a\xca\xd6\x16\x12\x90\x03=""" ) asn1 = xtt.asn1_from_ed25519_private_key(priv) decoded = der_decode(asn1, asn1Spec=rfc5208.PrivateKeyInfo(), decodeOpenTypes=True)[0] decoded_private_key = der_decode(decoded['privateKey'])[0].asOctets( ) # privateKey is itself another octet string self.assertEqual(decoded_private_key, priv.data[:32])
def __init__(self, type, format, algorithm, encoded, **kwargs): super(BksKeyEntry, self).__init__(**kwargs) self.type = type """An integer indicating the type of key: one of :const:`KEY_TYPE_PRIVATE`, :const:`KEY_TYPE_PUBLIC`, :const:`KEY_TYPE_SECRET`.""" self.format = format """A string indicating the format or encoding in which the key is stored. One of: ``PKCS8``, ``PKCS#8``, ``X.509``, ``X509``, ``RAW``.""" self.algorithm = algorithm """A string indicating the algorithm for which the key is valid.""" self.encoded = encoded """A byte string containing the key, formatted as indicated by the :attr:`format` attribute.""" if self.type == KEY_TYPE_PRIVATE: if self.format not in ["PKCS8", "PKCS#8"]: raise UnexpectedKeyEncodingException( "Unexpected encoding for private key entry: '%s'" % self.format) # self.encoded is a PKCS#8 PrivateKeyInfo private_key_info = decoder.decode( self.encoded, asn1Spec=rfc5208.PrivateKeyInfo())[0] self.pkey_pkcs8 = self.encoded self.pkey = private_key_info['privateKey'].asOctets() self.algorithm_oid = private_key_info['privateKeyAlgorithm'][ 'algorithm'].asTuple() elif self.type == KEY_TYPE_PUBLIC: if self.format not in ["X.509", "X509"]: raise UnexpectedKeyEncodingException( "Unexpected encoding for public key entry: '%s'" % self.format) # self.encoded is an X.509 SubjectPublicKeyInfo spki = decoder.decode(self.encoded, asn1Spec=rfc2459.SubjectPublicKeyInfo())[0] self.public_key_info = self.encoded self.public_key = bitstring_to_bytes(spki['subjectPublicKey']) self.algorithm_oid = spki['algorithm']['algorithm'].asTuple() elif self.type == KEY_TYPE_SECRET: if self.format != "RAW": raise UnexpectedKeyEncodingException( "Unexpected encoding for raw key entry: '%s'" % self.format) # self.encoded is an unwrapped/raw cryptographic key self.key = encoded self.key_size = len(encoded) * 8 else: raise UnexpectedKeyEncodingException( "Key format '%s' not recognized" % self.format)
def from_string(cls, key, password='******'): """Construct an RsaSigner instance from a string. Args: key: string, private key in PEM format. password: string, password for private key file. Unused for PEM files. Returns: RsaSigner instance. Raises: ValueError if the key cannot be parsed as PKCS#1 or PKCS#8 in PEM format. """ global _PKCS8_SPEC key = _helpers._from_bytes(key) # pem expects str in Py3 marker_id, key_bytes = pem.readPemBlocksFromFile( six.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER) if marker_id == 0: pkey = rsa.key.PrivateKey.load_pkcs1(key_bytes, format='DER') elif marker_id == 1: from pyasn1.codec.der import decoder from pyasn1_modules import rfc5208 if _PKCS8_SPEC is None: _PKCS8_SPEC = rfc5208.PrivateKeyInfo() key_info, remaining = decoder.decode(key_bytes, asn1Spec=_PKCS8_SPEC) if remaining != b'': raise ValueError('Unused bytes', remaining) pkey_info = key_info.getComponentByName('privateKey') pkey = rsa.key.PrivateKey.load_pkcs1(pkey_info.asOctets(), format='DER') else: raise ValueError('No key could be detected.') return cls(pkey)
def setUp(self): self.asn1Spec = rfc5208.PrivateKeyInfo()
$ cat pkcs8key.pem | %s""" % sys.argv[0]) sys.exit(-1) cnt = 0 while 1: idx, substrate = pem.readPemBlocksFromFile( sys.stdin, ('-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----'), ('-----BEGIN ENCRYPTED PRIVATE KEY-----', '-----END ENCRYPTED PRIVATE KEY-----')) if not substrate: break if idx == 0: asn1Spec = rfc5208.PrivateKeyInfo() elif idx == 1: asn1Spec = rfc5208.EncryptedPrivateKeyInfo() else: break key, rest = decoder.decode(substrate, asn1Spec=asn1Spec) if rest: substrate = substrate[:-len(rest)] print(key.prettyPrint()) assert encoder.encode(key) == substrate, 'pkcs8 recode fails' cnt = cnt + 1