From b0d454da9a9a19c019a6a86c5a4f44175dfeb442 Mon Sep 17 00:00:00 2001 From: Peter Hamilton Date: Tue, 15 Aug 2017 11:03:20 -0400 Subject: [PATCH] Add ProxyKmipClient demos for the Encrypt / Decrypt operations This change adds demos for the ProxyKmipClient, demonstrating how to encrypt and decrypt messages. Demo utilities have been updated to support the new demo scripts and the KMIPProxy client has been updated to correctly return operation results. --- kmip/demos/pie/decrypt.py | 77 ++++++++++++++ kmip/demos/pie/encrypt.py | 103 +++++++++++++++++++ kmip/demos/utils.py | 30 ++++++ kmip/services/kmip_client.py | 24 +++-- kmip/tests/unit/services/test_kmip_client.py | 4 +- 5 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 kmip/demos/pie/decrypt.py create mode 100644 kmip/demos/pie/encrypt.py diff --git a/kmip/demos/pie/decrypt.py b/kmip/demos/pie/decrypt.py new file mode 100644 index 0000000..1b10aa6 --- /dev/null +++ b/kmip/demos/pie/decrypt.py @@ -0,0 +1,77 @@ +# Copyright (c) 2017 The Johns Hopkins University/Applied Physics Laboratory +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import binascii +import logging +import sys + +from kmip.core import enums +from kmip.demos import utils +from kmip.pie import client + +# Real world example, assuming 'test' is a valid configuration: +# +# $ python kmip/demos/pie/encrypt.py -c test -m "My test message." +# INFO - Successfully created a new encryption key. +# INFO - Secret ID: 470 +# INFO - Successfully activated the encryption key. +# INFO - Successfully encrypted the message. +# INFO - Cipher text: b'49cfacbb62659180c20dfbf9f7553488b3ea9ebeecd70ce2e5c4d4 +# ece6def0d4' +# INFO - No autogenerated IV expected, since one was provided. +# INFO - Autogenerated IV: None +# $ python kmip/demos/pie/decrypt.py -c test -i 470 -m b'49cfacbb62659180c20df +# bf9f7553488b3ea9ebeecd70ce2e5c4d4ece6def0d4' +# INFO - Successfully decrypted the message. +# INFO - Plain text: 'My test message.' + + +if __name__ == '__main__': + logger = utils.build_console_logger(logging.INFO) + + # Build and parse arguments + parser = utils.build_cli_parser(enums.Operation.DECRYPT) + opts, args = parser.parse_args(sys.argv[1:]) + config = opts.config + uuid = opts.uuid + message = opts.message + + if not message.startswith("b"): + raise ValueError("The message should be a byte string (e.g., b'...').") + else: + message = binascii.unhexlify(message[1:]) + + # Build the client and connect to the server + with client.ProxyKmipClient(config=config) as client: + # Decrypt the cipher text with the encryption key. + try: + plain_text = client.decrypt( + message, + uid=uuid, + cryptographic_parameters={ + 'cryptographic_algorithm': + enums.CryptographicAlgorithm.AES, + 'block_cipher_mode': enums.BlockCipherMode.CBC, + 'padding_method': enums.PaddingMethod.ANSI_X923 + }, + iv_counter_nonce=( + b'\x01\x7D\x45\xA0\x88\x08\x11\x11' + b'\xF0\x00\x12\xFF\x7A\x3A\x36\x90' + ) + ) + logger.info("Successfully decrypted the message.") + logger.info("Plain text: '{0}'".format(plain_text.decode('utf-8'))) + except Exception as e: + logger.error(e) diff --git a/kmip/demos/pie/encrypt.py b/kmip/demos/pie/encrypt.py new file mode 100644 index 0000000..1946eeb --- /dev/null +++ b/kmip/demos/pie/encrypt.py @@ -0,0 +1,103 @@ +# Copyright (c) 2017 The Johns Hopkins University/Applied Physics Laboratory +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import binascii +import logging +import sys + +from kmip.core import enums +from kmip.demos import utils +from kmip.pie import client + +# Real world example, assuming 'test' is a valid configuration: +# +# $ python kmip/demos/pie/encrypt.py -c test -m "My test message." +# INFO - Successfully created a new encryption key. +# INFO - Secret ID: 470 +# INFO - Successfully activated the encryption key. +# INFO - Successfully encrypted the message. +# INFO - Cipher text: b'49cfacbb62659180c20dfbf9f7553488b3ea9ebeecd70ce2e5c4d4 +# ece6def0d4' +# INFO - No autogenerated IV expected, since one was provided. +# INFO - Autogenerated IV: None +# $ python kmip/demos/pie/decrypt.py -c test -i 470 -m b'49cfacbb62659180c20df +# bf9f7553488b3ea9ebeecd70ce2e5c4d4ece6def0d4' +# INFO - Successfully decrypted the message. +# INFO - Plain text: 'My test message.' + + +if __name__ == '__main__': + logger = utils.build_console_logger(logging.INFO) + + # Build and parse arguments + parser = utils.build_cli_parser(enums.Operation.ENCRYPT) + opts, args = parser.parse_args(sys.argv[1:]) + config = opts.config + message = opts.message + + message = bytes(message, 'utf-8') + + # Build the client and connect to the server + with client.ProxyKmipClient(config=config) as client: + # Create an encryption key. + try: + key_id = client.create( + enums.CryptographicAlgorithm.AES, + 128, + cryptographic_usage_mask=[ + enums.CryptographicUsageMask.ENCRYPT, + enums.CryptographicUsageMask.DECRYPT + ] + ) + logger.info("Successfully created a new encryption key.") + logger.info("Secret ID: {0}".format(key_id)) + except Exception as e: + logger.error(e) + sys.exit(-1) + + # Activate the encryption key so that it can be used. + try: + client.activate(key_id) + logger.info("Successfully activated the encryption key.") + except Exception as e: + logger.error(e) + sys.exit(-1) + + # Encrypt some data with the encryption key. + try: + cipher_text, autogenerated_iv = client.encrypt( + message, + uid=key_id, + cryptographic_parameters={ + 'cryptographic_algorithm': + enums.CryptographicAlgorithm.AES, + 'block_cipher_mode': enums.BlockCipherMode.CBC, + 'padding_method': enums.PaddingMethod.ANSI_X923 + }, + iv_counter_nonce=( + b'\x01\x7D\x45\xA0\x88\x08\x11\x11' + b'\xF0\x00\x12\xFF\x7A\x3A\x36\x90' + ) + ) + logger.info("Successfully encrypted the message.") + logger.info( + "Cipher text: {0}".format(binascii.hexlify(cipher_text)) + ) + logger.info( + "No autogenerated IV expected, since one was provided." + ) + logger.info("Autogenerated IV: {0}".format(autogenerated_iv)) + except Exception as e: + logger.error(e) diff --git a/kmip/demos/utils.py b/kmip/demos/utils.py index b6d7796..fd54e1d 100644 --- a/kmip/demos/utils.py +++ b/kmip/demos/utils.py @@ -240,6 +240,36 @@ def build_cli_parser(operation=None): default=None, dest="algorithm", help="Encryption algorithm for the secret (e.g., AES)") + elif operation is Operation.ENCRYPT: + parser.add_option( + "-m", + "--message", + action="store", + type="str", + default="This is a secret message.", + dest="message", + help="The message to encrypt." + ) + elif operation is Operation.DECRYPT: + parser.add_option( + "-i", + "--uuid", + action="store", + type="str", + default=None, + dest="uuid", + help="The unique ID of the decryption key to use to decrypt the " + "cipher text." + ) + parser.add_option( + "-m", + "--message", + action="store", + type="str", + default=None, + dest="message", + help="The cipher text to decrypt." + ) return parser diff --git a/kmip/services/kmip_client.py b/kmip/services/kmip_client.py index e8241e8..8ab39a4 100644 --- a/kmip/services/kmip_client.py +++ b/kmip/services/kmip_client.py @@ -584,9 +584,15 @@ class KMIPProxy(KMIP): result['data'] = payload.data result['iv_counter_nonce'] = payload.iv_counter_nonce - result['result_status'] = batch_item.result_status - result['result_reason'] = batch_item.result_reason - result['result_message'] = batch_item.result_message + result['result_status'] = batch_item.result_status.value + try: + result['result_reason'] = batch_item.result_reason.value + except: + result['result_reason'] = batch_item.result_reason + try: + result['result_message'] = batch_item.result_message.value + except: + result['result_message'] = batch_item.result_message return result @@ -653,9 +659,15 @@ class KMIPProxy(KMIP): result['unique_identifier'] = payload.unique_identifier result['data'] = payload.data - result['result_status'] = batch_item.result_status - result['result_reason'] = batch_item.result_reason - result['result_message'] = batch_item.result_message + result['result_status'] = batch_item.result_status.value + try: + result['result_reason'] = batch_item.result_reason.value + except: + result['result_reason'] = batch_item.result_reason + try: + result['result_message'] = batch_item.result_message.value + except: + result['result_message'] = batch_item.result_message return result diff --git a/kmip/tests/unit/services/test_kmip_client.py b/kmip/tests/unit/services/test_kmip_client.py index cfddde3..dded6d5 100644 --- a/kmip/tests/unit/services/test_kmip_client.py +++ b/kmip/tests/unit/services/test_kmip_client.py @@ -839,7 +839,7 @@ class TestKMIPClient(TestCase): self.assertEqual(None, result.get('iv_counter_nonce')) self.assertEqual( ResultStatusEnum.SUCCESS, - result.get('result_status').value + result.get('result_status') ) self.assertEqual(None, result.get('result_reason')) self.assertEqual(None, result.get('result_message')) @@ -901,7 +901,7 @@ class TestKMIPClient(TestCase): ) self.assertEqual( ResultStatusEnum.SUCCESS, - result.get('result_status').value + result.get('result_status') ) self.assertEqual(None, result.get('result_reason')) self.assertEqual(None, result.get('result_message'))