def test_rsa_private_pkcs1v15_decrypt(self): original_data = b'This is the message to sign' private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test.key')) with open(os.path.join(fixtures_dir, 'rsa_public_encrypted'), 'rb') as f: plaintext = asymmetric.rsa_pkcs1v15_decrypt(private, f.read()) self.assertEqual(original_data, plaintext)
def test_demo_plugin(): with_plugin_cfg = CertomancerConfig.from_file('tests/data/with-plugin.yml', 'tests/data') with_plugin_app = Animator(AnimatorArchStore(with_plugin_cfg.pki_archs), with_web_ui=False) client = Client(with_plugin_app, Response) # make the endpoint encrypt something endpoint = '/testing-ca/plugin/encrypt-echo/test-endpoint' payload = b'test test test' response = client.post(endpoint, data=payload) # decrypt it env_data = cms.ContentInfo.load(response.data)['content'] arch = with_plugin_cfg.get_pki_arch(ArchLabel('testing-ca')) key = arch.key_set.get_private_key(KeyLabel('signer1')) ktri = env_data['recipient_infos'][0].chosen encrypted_key = ktri['encrypted_key'].native decrypted_key = asymmetric.rsa_pkcs1v15_decrypt( asymmetric.load_private_key(key.dump()), encrypted_key) eci = env_data['encrypted_content_info'] cea = eci['content_encryption_algorithm'] assert cea['algorithm'].native == 'aes256_cbc' iv = cea['parameters'].native encrypted_content_bytes = eci['encrypted_content'].native decrypted_payload = symmetric.aes_cbc_pkcs7_decrypt( decrypted_key, encrypted_content_bytes, iv) assert decrypted_payload == payload
def decrypt_message(encrypted_data, decryption_key): """Function parses an ASN.1 encrypted message and extracts/decrypts the original message. :param encrypted_data: A CMS ASN.1 byte string containing the encrypted data. :param decryption_key: The key to be used for decrypting the data. :return: A byte string containing the decrypted original message. """ cms_content = cms.ContentInfo.load(encrypted_data) cipher, decrypted_content = None, None if cms_content['content_type'].native == 'enveloped_data': recipient_info = cms_content['content']['recipient_infos'][0].parse() key_enc_alg = recipient_info['key_encryption_algorithm'][ 'algorithm'].native encrypted_key = recipient_info['encrypted_key'].native if key_enc_alg == 'rsa': try: key = asymmetric.rsa_pkcs1v15_decrypt(decryption_key[0], encrypted_key) except Exception: raise DecryptionError( 'Failed to decrypt the payload: Could not extract decryption key.' ) alg = cms_content['content']['encrypted_content_info'][ 'content_encryption_algorithm'] encapsulated_data = cms_content['content'][ 'encrypted_content_info']['encrypted_content'].native try: if alg['algorithm'].native == '1.2.840.113549.3.4': # This is RC4 decrypted_content = symmetric.rc4_decrypt( key, encapsulated_data) elif alg.encryption_cipher == 'tripledes': cipher = 'tripledes_192_cbc' decrypted_content = symmetric.tripledes_cbc_pkcs5_decrypt( key, encapsulated_data, alg.encryption_iv) elif alg.encryption_cipher == 'aes': decrypted_content = symmetric.aes_cbc_pkcs7_decrypt( key, encapsulated_data, alg.encryption_iv) elif alg.encryption_cipher == 'rc2': decrypted_content = symmetric.rc2_cbc_pkcs5_decrypt( key, encapsulated_data, alg['parameters']['iv'].native) else: raise AS2Exception('Unsupported Encryption Algorithm') except Exception as e: raise DecryptionError( 'Failed to decrypt the payload: {}'.format(e)) else: raise AS2Exception('Unsupported Encryption Algorithm') else: raise DecryptionError('Encrypted data not found in ASN.1 ') return cipher, decrypted_content
def test_demo_plugin(requests_mock): with_plugin_cfg = CertomancerConfig.from_file('tests/data/with-plugin.yml', 'tests/data') arch = with_plugin_cfg.get_pki_arch(ArchLabel('testing-ca')) illusionist.Illusionist(pki_arch=arch).register(requests_mock) importlib.import_module('example_plugin.encrypt_echo') # make the endpoint encrypt something endpoint = 'http://test.test/testing-ca/plugin/encrypt-echo/test-endpoint' payload = b'test test test' response = requests.post(endpoint, data=payload) # decrypt it env_data = cms.ContentInfo.load(response.content)['content'] key = arch.key_set.get_private_key(KeyLabel('signer1')) ktri = env_data['recipient_infos'][0].chosen encrypted_key = ktri['encrypted_key'].native decrypted_key = asymmetric.rsa_pkcs1v15_decrypt( asymmetric.load_private_key(key.dump()), encrypted_key) eci = env_data['encrypted_content_info'] cea = eci['content_encryption_algorithm'] assert cea['algorithm'].native == 'aes256_cbc' iv = cea['parameters'].native encrypted_content_bytes = eci['encrypted_content'].native decrypted_payload = symmetric.aes_cbc_pkcs7_decrypt( decrypted_key, encrypted_content_bytes, iv) assert decrypted_payload == payload
def decrypt_message(encrypted_data, decryption_key): """Function parses an ASN.1 encrypted message and extracts/decrypts the original message. :param encrypted_data: A CMS ASN.1 byte string containing the encrypted data. :param decryption_key: The key to be used for decrypting the data. :return: A byte string containing the decrypted original message. """ cms_content = cms.ContentInfo.load(encrypted_data) cipher, decrypted_content = None, None if cms_content["content_type"].native == "enveloped_data": recipient_info = cms_content["content"]["recipient_infos"][0].parse() key_enc_alg = recipient_info["key_encryption_algorithm"][ "algorithm"].native encrypted_key = recipient_info["encrypted_key"].native if cms.KeyEncryptionAlgorithmId( key_enc_alg) == cms.KeyEncryptionAlgorithmId("rsa"): try: key = asymmetric.rsa_pkcs1v15_decrypt(decryption_key[0], encrypted_key) except Exception: raise DecryptionError( "Failed to decrypt the payload: Could not extract decryption key." ) alg = cms_content["content"]["encrypted_content_info"][ "content_encryption_algorithm"] encapsulated_data = cms_content["content"][ "encrypted_content_info"]["encrypted_content"].native try: if alg["algorithm"].native == "rc4": decrypted_content = symmetric.rc4_decrypt( key, encapsulated_data) elif alg.encryption_cipher == "tripledes": cipher = "tripledes_192_cbc" decrypted_content = symmetric.tripledes_cbc_pkcs5_decrypt( key, encapsulated_data, alg.encryption_iv) elif alg.encryption_cipher == "aes": decrypted_content = symmetric.aes_cbc_pkcs7_decrypt( key, encapsulated_data, alg.encryption_iv) elif alg.encryption_cipher == "rc2": decrypted_content = symmetric.rc2_cbc_pkcs5_decrypt( key, encapsulated_data, alg["parameters"]["iv"].native) else: raise AS2Exception("Unsupported Encryption Algorithm") except Exception as e: raise DecryptionError( "Failed to decrypt the payload: {}".format(e)) else: raise AS2Exception("Unsupported Encryption Algorithm") else: raise DecryptionError("Encrypted data not found in ASN.1 ") return cipher, decrypted_content
def test_rsa_pkcs1v15_encrypt(self): original_data = b'This is data to encrypt' private = asymmetric.load_private_key(os.path.join(fixtures_dir, 'keys/test.key')) public = asymmetric.load_public_key(os.path.join(fixtures_dir, 'keys/test.crt')) ciphertext = asymmetric.rsa_pkcs1v15_encrypt(public, original_data) self.assertIsInstance(ciphertext, byte_cls) plaintext = asymmetric.rsa_pkcs1v15_decrypt(private, ciphertext) self.assertEqual(original_data, plaintext)
def on_get(self, req, resp): operation = req.get_param("operation", required=True) if operation.lower() == "getcacert": resp.body = keys.parse_certificate( self.authority.certificate_buf).dump() resp.append_header("Content-Type", "application/x-x509-ca-cert") return # If we bump into exceptions later encrypted_container = b"" attr_list = [ cms.CMSAttribute({ 'type': "message_type", 'values': ["3"] }), cms.CMSAttribute({ 'type': "pki_status", 'values': ["2"] # rejected }) ] try: info = cms.ContentInfo.load( b64decode(req.get_param("message", required=True))) ############################################### ### Verify signature of the outer container ### ############################################### signed_envelope = info['content'] encap_content_info = signed_envelope['encap_content_info'] encap_content = encap_content_info['content'] # TODO: try except current_certificate, = signed_envelope["certificates"] signer, = signed_envelope["signer_infos"] # TODO: compare cert to current one if we are renewing assert signer["digest_algorithm"]["algorithm"].native == "md5" assert signer["signature_algorithm"][ "algorithm"].native == "rsassa_pkcs1v15" message_digest = None transaction_id = None sender_nonce = None for attr in signer["signed_attrs"]: if attr["type"].native == "sender_nonce": sender_nonce, = attr["values"] elif attr["type"].native == "trans_id": transaction_id, = attr["values"] elif attr["type"].native == "message_digest": message_digest, = attr["values"] if hashlib.md5(encap_content.native).digest( ) != message_digest.native: raise SCEPBadMessageCheck() assert message_digest msg = signer["signed_attrs"].dump(force=True) assert msg[0] == 160 # Verify signature try: asymmetric.rsa_pkcs1v15_verify( asymmetric.load_certificate(current_certificate.dump()), signer["signature"].native, b"\x31" + msg[1:], # wtf?! "md5") except SignatureError: raise SCEPBadMessageCheck() ############################### ### Decrypt inner container ### ############################### info = cms.ContentInfo.load(encap_content.native) encrypted_envelope = info['content'] encrypted_content_info = encrypted_envelope[ 'encrypted_content_info'] iv = encrypted_content_info['content_encryption_algorithm'][ 'parameters'].native if encrypted_content_info['content_encryption_algorithm'][ "algorithm"].native != "des": raise SCEPBadAlgo() encrypted_content = encrypted_content_info[ 'encrypted_content'].native recipient, = encrypted_envelope['recipient_infos'] if recipient.native["rid"][ "serial_number"] != self.authority.certificate.serial_number: raise SCEPBadCertId() # Since CA private key is not directly readable here, we'll redirect it to signer socket key = asymmetric.rsa_pkcs1v15_decrypt( self.authority.private_key, recipient.native["encrypted_key"]) if len(key) == 8: key = key * 3 # Convert DES to 3DES buf = symmetric.tripledes_cbc_pkcs5_decrypt( key, encrypted_content, iv) _, _, common_name = self.authority.store_request(buf, overwrite=True) cert, buf = self.authority.sign(common_name, overwrite=True) signed_certificate = asymmetric.load_certificate(buf) content = signed_certificate.asn1.dump() except SCEPError as e: attr_list.append( cms.CMSAttribute({ 'type': "fail_info", 'values': ["%d" % e.code] })) else: ################################## ### Degenerate inner container ### ################################## degenerate = cms.ContentInfo({ 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", 'certificates': [signed_certificate.asn1], 'digest_algorithms': [cms.DigestAlgorithm({'algorithm': "md5"})], 'encap_content_info': { 'content_type': "data", 'content': cms.ContentInfo({ 'content_type': "signed_data", 'content': None }).dump() }, 'signer_infos': [] }) }) ################################ ### Encrypt middle container ### ################################ key = os.urandom(8) iv, encrypted_content = symmetric.des_cbc_pkcs5_encrypt( key, degenerate.dump(), os.urandom(8)) assert degenerate.dump() == symmetric.tripledes_cbc_pkcs5_decrypt( key * 3, encrypted_content, iv) ri = cms.RecipientInfo({ 'ktri': cms.KeyTransRecipientInfo({ 'version': "v0", 'rid': cms.RecipientIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': current_certificate.chosen["tbs_certificate"] ["issuer"], 'serial_number': current_certificate.chosen["tbs_certificate"] ["serial_number"], }), }), 'key_encryption_algorithm': { 'algorithm': "rsa" }, 'encrypted_key': asymmetric.rsa_pkcs1v15_encrypt( asymmetric.load_certificate( current_certificate.chosen.dump()), key) }) }) encrypted_container = cms.ContentInfo({ 'content_type': "enveloped_data", 'content': cms.EnvelopedData({ 'version': "v1", 'recipient_infos': [ri], 'encrypted_content_info': { 'content_type': "data", 'content_encryption_algorithm': { 'algorithm': "des", 'parameters': iv }, 'encrypted_content': encrypted_content } }) }).dump() attr_list = [ cms.CMSAttribute({ 'type': "message_digest", 'values': [hashlib.sha1(encrypted_container).digest()] }), cms.CMSAttribute({ 'type': "message_type", 'values': ["3"] }), cms.CMSAttribute({ 'type': "pki_status", 'values': ["0"] # ok }) ] finally: ############################## ### Signed outer container ### ############################## attrs = cms.CMSAttributes(attr_list + [ cms.CMSAttribute({ 'type': "recipient_nonce", 'values': [sender_nonce] }), cms.CMSAttribute({ 'type': "trans_id", 'values': [transaction_id] }) ]) signer = cms.SignerInfo({ "signed_attrs": attrs, 'version': "v1", 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': self.authority.certificate.issuer, 'serial_number': self.authority.certificate.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': "sha1"}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': "rsassa_pkcs1v15"}), 'signature': asymmetric.rsa_pkcs1v15_sign(self.authority.private_key, b"\x31" + attrs.dump()[1:], "sha1") }) resp.append_header("Content-Type", "application/x-pki-message") resp.body = cms.ContentInfo({ 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", 'certificates': [self.authority.certificate], 'digest_algorithms': [cms.DigestAlgorithm({'algorithm': "sha1"})], 'encap_content_info': { 'content_type': "data", 'content': encrypted_container }, 'signer_infos': [signer] }) }).dump()
def decrypt(self, message): return asymmetric.rsa_pkcs1v15_decrypt(self.pair[1], message)
def on_get(self, req, resp): operation = req.get_param("operation", required=True) if operation == "GetCACert": resp.body = keys.parse_certificate( self.authority.certificate_buf).dump() resp.append_header("Content-Type", "application/x-x509-ca-cert") return elif operation == "GetCACaps": # TODO: return renewal flag based on renewal subnets config option resp.body = "Renewal\nMD5\nSHA-1\nSHA-256\nSHA-512\nDES3\n" return elif operation == "PKIOperation": pass else: raise falcon.HTTPBadRequest("Bad request", "Unknown operation %s" % operation) # If we bump into exceptions later encrypted_container = b"" attr_list = [ cms.CMSAttribute({ 'type': "message_type", 'values': ["3"] }), cms.CMSAttribute({ 'type': "pki_status", 'values': ["2"] # rejected }) ] try: info = cms.ContentInfo.load( b64decode(req.get_param("message", required=True))) ############################################### ### Verify signature of the outer container ### ############################################### signed_envelope = info['content'] encap_content_info = signed_envelope['encap_content_info'] encap_content = encap_content_info['content'] # TODO: try except current_certificate, = signed_envelope["certificates"] signer, = signed_envelope["signer_infos"] # TODO: compare cert to current one if we are renewing digest_algorithm = signer["digest_algorithm"]["algorithm"].native signature_algorithm = signer["signature_algorithm"][ "algorithm"].native if digest_algorithm not in ("md5", "sha1", "sha256", "sha512"): raise SCEPBadAlgo() if signature_algorithm != "rsassa_pkcs1v15": raise SCEPBadAlgo() message_digest = None transaction_id = None sender_nonce = None for attr in signer["signed_attrs"]: if attr["type"].native == "sender_nonce": sender_nonce, = attr["values"] elif attr["type"].native == "trans_id": transaction_id, = attr["values"] elif attr["type"].native == "message_digest": message_digest, = attr["values"] if getattr(hashlib, digest_algorithm)(encap_content.native).digest( ) != message_digest.native: raise SCEPDigestMismatch() if not sender_nonce: raise SCEPBadRequest() if not transaction_id: raise SCEPBadRequest() assert message_digest msg = signer["signed_attrs"].dump(force=True) assert msg[0] == 160 # Verify signature try: asymmetric.rsa_pkcs1v15_verify( asymmetric.load_certificate(current_certificate.dump()), signer["signature"].native, b"\x31" + msg[1:], # wtf?! "md5") except SignatureError: raise SCEPSignatureMismatch() ############################### ### Decrypt inner container ### ############################### info = cms.ContentInfo.load(encap_content.native) encrypted_envelope = info['content'] encrypted_content_info = encrypted_envelope[ 'encrypted_content_info'] iv = encrypted_content_info['content_encryption_algorithm'][ 'parameters'].native if encrypted_content_info['content_encryption_algorithm'][ "algorithm"].native != "des": raise SCEPBadAlgo() encrypted_content = encrypted_content_info[ 'encrypted_content'].native recipient, = encrypted_envelope['recipient_infos'] if recipient.native["rid"][ "serial_number"] != self.authority.certificate.serial_number: raise SCEPBadCertId() key = asymmetric.rsa_pkcs1v15_decrypt( self.authority.private_key, recipient.native["encrypted_key"]) if len(key) == 8: key = key * 3 # Convert DES to 3DES buf = symmetric.tripledes_cbc_pkcs5_decrypt( key, encrypted_content, iv) _, _, common_name = self.authority.store_request(buf, overwrite=True) logger.info( "SCEP client from %s requested with %s digest algorithm, %s signature", req.context["remote_addr"], digest_algorithm, signature_algorithm) cert, buf = self.authority.sign(common_name, profile=config.PROFILES["gw"], overwrite=True) signed_certificate = asymmetric.load_certificate(buf) content = signed_certificate.asn1.dump() except SCEPError as e: attr_list.append( cms.CMSAttribute({ 'type': "fail_info", 'values': ["%d" % e.code] })) logger.info("Failed to sign SCEP request due to: %s" % e.explaination) else: ################################## ### Degenerate inner container ### ################################## degenerate = cms.ContentInfo({ 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", 'certificates': [signed_certificate.asn1], 'digest_algorithms': [cms.DigestAlgorithm({'algorithm': digest_algorithm})], 'encap_content_info': { 'content_type': "data", 'content': cms.ContentInfo({ 'content_type': "signed_data", 'content': None }).dump() }, 'signer_infos': [] }) }) ################################ ### Encrypt middle container ### ################################ key = os.urandom(8) iv, encrypted_content = symmetric.des_cbc_pkcs5_encrypt( key, degenerate.dump(), os.urandom(8)) assert degenerate.dump() == symmetric.tripledes_cbc_pkcs5_decrypt( key * 3, encrypted_content, iv) ri = cms.RecipientInfo({ 'ktri': cms.KeyTransRecipientInfo({ 'version': "v0", 'rid': cms.RecipientIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': current_certificate.chosen["tbs_certificate"] ["issuer"], 'serial_number': current_certificate.chosen["tbs_certificate"] ["serial_number"], }), }), 'key_encryption_algorithm': { 'algorithm': "rsa" }, 'encrypted_key': asymmetric.rsa_pkcs1v15_encrypt( asymmetric.load_certificate( current_certificate.chosen.dump()), key) }) }) encrypted_container = cms.ContentInfo({ 'content_type': "enveloped_data", 'content': cms.EnvelopedData({ 'version': "v1", 'recipient_infos': [ri], 'encrypted_content_info': { 'content_type': "data", 'content_encryption_algorithm': { 'algorithm': "des", 'parameters': iv }, 'encrypted_content': encrypted_content } }) }).dump() attr_list = [ cms.CMSAttribute({ 'type': "message_digest", 'values': [ getattr( hashlib, digest_algorithm)(encrypted_container).digest() ] }), cms.CMSAttribute({ 'type': "message_type", 'values': ["3"] }), cms.CMSAttribute({ 'type': "pki_status", 'values': ["0"] # ok }) ] finally: ############################## ### Signed outer container ### ############################## attrs = cms.CMSAttributes(attr_list + [ cms.CMSAttribute({ 'type': "recipient_nonce", 'values': [sender_nonce] }), cms.CMSAttribute({ 'type': "trans_id", 'values': [transaction_id] }) ]) signer = cms.SignerInfo({ "signed_attrs": attrs, 'version': "v1", 'sid': cms.SignerIdentifier({ 'issuer_and_serial_number': cms.IssuerAndSerialNumber({ 'issuer': self.authority.certificate.issuer, 'serial_number': self.authority.certificate.serial_number, }), }), 'digest_algorithm': algos.DigestAlgorithm({'algorithm': digest_algorithm}), 'signature_algorithm': algos.SignedDigestAlgorithm({'algorithm': "rsassa_pkcs1v15"}), 'signature': asymmetric.rsa_pkcs1v15_sign(self.authority.private_key, b"\x31" + attrs.dump()[1:], digest_algorithm) }) resp.append_header("Content-Type", "application/x-pki-message") resp.body = cms.ContentInfo({ 'content_type': "signed_data", 'content': cms.SignedData({ 'version': "v1", 'certificates': [self.authority.certificate], 'digest_algorithms': [cms.DigestAlgorithm({'algorithm': digest_algorithm})], 'encap_content_info': { 'content_type': "data", 'content': encrypted_container }, 'signer_infos': [signer] }) }).dump()