def encrypt(self, key_password): """ Encrypts the private key, so that it can be saved to a keystore. This will make it necessary to decrypt it again if it is going to be used later. Has no effect if the entry is already encrypted. :param str key_password: The password to encrypt the entry with. """ if not self.is_decrypted(): return encrypted_private_key = sun_crypto.jks_pkey_encrypt( self.pkey_pkcs8, key_password) a = AlgorithmIdentifier() a.setComponentByName('algorithm', sun_crypto.SUN_JKS_ALGO_ID) a.setComponentByName('parameters', '\x05\x00') epki = rfc5208.EncryptedPrivateKeyInfo() epki.setComponentByName('encryptionAlgorithm', a) epki.setComponentByName('encryptedData', encrypted_private_key) self._encrypted = encoder.encode(epki) self._pkey = None self._pkey_pkcs8 = None self._algorithm_oid = None
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 setUp(self): self.asn1Spec = rfc5208.EncryptedPrivateKeyInfo()
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 print('*** %s PKCS#8 key(s) de/serialized' % cnt)