Refactor, add encrypt/decrypt data dict functions to crypt

Just a refactor, no change in functionality.

The functions added to crypt are used to encrypt / decrypt resource
properties data dicts. Note that they should not be used for
encrypting / decrypting other things such as params or user creds
(which are just strings).  An intermediate json conversion of each
value in a dict takes place before it is encrypted/decrypted.

Change-Id: Id6bcc90cbf430095719315ac7e9d3e8c9e745012
This commit is contained in:
Crag Wolfe 2016-08-28 20:33:20 -04:00
parent 0925692ecd
commit a673ee2d56
3 changed files with 53 additions and 13 deletions

View File

@ -17,6 +17,7 @@ import sys
from Crypto.Cipher import AES
from cryptography import fernet
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import importutils
@ -92,6 +93,31 @@ def decrypt(method, data, encryption_key=None):
return encodeutils.safe_decode(value, 'utf-8')
def encrypted_dict(data, encryption_key=None):
'Return an encrypted dict. Values converted to json before encrypted'
return_data = {}
if not data:
return return_data
for prop_name, prop_value in data.items():
prop_string = jsonutils.dumps(prop_value)
encrypted_value = encrypt(prop_string, encryption_key)
return_data[prop_name] = encrypted_value
return return_data
def decrypted_dict(data, encryption_key=None):
'Return a decrypted dict. Assume input values are encrypted json fields.'
return_data = {}
if not data:
return return_data
for prop_name, prop_value in data.items():
method, value = prop_value
decrypted_value = decrypt(method, value, encryption_key)
prop_string = jsonutils.loads(decrypted_value)
return_data[prop_name] = prop_string
return return_data
def oslo_decrypt_v1(value, encryption_key=None):
encryption_key = get_valid_encryption_key(encryption_key)
sym = SymmetricCrypto()

View File

@ -18,7 +18,6 @@
import collections
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_versionedobjects import base
from oslo_versionedobjects import fields
import six
@ -104,13 +103,8 @@ class Resource(
resource[field] = db_resource[field]
if resource.properties_data_encrypted and resource.properties_data:
properties_data = {}
for prop_name, prop_value in resource.properties_data.items():
method, value = prop_value
decrypted_value = crypt.decrypt(method, value)
prop_string = jsonutils.loads(decrypted_value)
properties_data[prop_name] = prop_string
resource.properties_data = properties_data
decrypted_data = crypt.decrypted_dict(resource.properties_data)
resource.properties_data = decrypted_data
resource._context = context
resource.obj_reset_changes()
@ -237,11 +231,7 @@ class Resource(
@staticmethod
def encrypt_properties_data(data):
if cfg.CONF.encrypt_parameters_and_properties and data:
result = {}
for prop_name, prop_value in data.items():
prop_string = jsonutils.dumps(prop_value)
encrypted_value = crypt.encrypt(prop_string)
result[prop_name] = encrypted_value
result = crypt.encrypted_dict(data)
return (True, result)
return (False, data)

View File

@ -37,3 +37,27 @@ class CryptTest(common.HeatTestCase):
exp_msg = ('heat.conf misconfigured, auth_encryption_key '
'must be 32 characters')
self.assertIn(exp_msg, six.text_type(err))
def _test_encrypt_decrypt_dict(self, encryption_key=None):
data = {'p1': u'happy',
'2': [u'a', u'little', u'blue'],
'p3': {u'really': u'exited', u'ok int': 9},
'4': u'',
'p5': True,
'6': 7}
encrypted_data = crypt.encrypted_dict(data, encryption_key)
for k in encrypted_data:
self.assertEqual('cryptography_decrypt_v1',
encrypted_data[k][0])
self.assertEqual(2, len(encrypted_data[k]))
# the keys remain the same
self.assertEqual(set(data), set(encrypted_data))
decrypted_data = crypt.decrypted_dict(encrypted_data, encryption_key)
self.assertEqual(data, decrypted_data)
def test_encrypt_decrypt_dict_custom_enc_key(self):
self._test_encrypt_decrypt_dict('just for testing not so great re')
def test_encrypt_decrypt_dict_default_enc_key(self):
self._test_encrypt_decrypt_dict()