def __init__(self, config): super(SessionAction, self).__init__(config) #self._username = self.config['username'] #self._password = self.config['password'] #self._enable_username = self.config['enable_username'] #self._enable_password = self.config['enable_password'] # Get Encryption Setup and Key is_encryption_enabled = cfg.CONF.keyvalue.enable_encryption if is_encryption_enabled: crypto_key_path = cfg.CONF.keyvalue.encryption_key_path with open(crypto_key_path) as key_file: crypto_key = AesKey.Read(key_file.read()) # Retrieve and decrypt values client = Client(base_url='http://localhost') key = client.keys.get_by_name('campus_ztp.username') if key: self._username = key.value key = client.keys.get_by_name('campus_ztp.password') if key: self._password = symmetric_decrypt(crypto_key, key.value) key = client.keys.get_by_name('campus_ztp.enable_username') if key: self._enable_username = key.value key = client.keys.get_by_name('campus_ztp.enable_password') if key: self._enable_password = symmetric_decrypt(crypto_key, key.value)
def test_symmetric_encrypt_decrypt(self): original = 'secret' crypto = crypto_utils.symmetric_encrypt( CryptoUtilsTestCase.test_crypto_key, original) plain = crypto_utils.symmetric_decrypt( CryptoUtilsTestCase.test_crypto_key, crypto) self.assertEqual(plain, original)
def from_model(cls, model, mask_secrets=True): if not KeyValuePairAPI.crypto_setup: KeyValuePairAPI._setup_crypto() doc = cls._from_model(model, mask_secrets=mask_secrets) if getattr(model, 'expire_timestamp', None) and model.expire_timestamp: doc['expire_timestamp'] = isotime.format(model.expire_timestamp, offset=False) encrypted = False secret = getattr(model, 'secret', False) if secret: encrypted = True if not mask_secrets and secret: doc['value'] = symmetric_decrypt(KeyValuePairAPI.crypto_key, model.value) encrypted = False scope = getattr(model, 'scope', SYSTEM_SCOPE) if scope: doc['scope'] = scope key = doc.get('name', None) if scope == USER_SCOPE and key: doc['user'] = UserKeyReference.get_user(key) doc['name'] = UserKeyReference.get_name(key) doc['encrypted'] = encrypted attrs = {attr: value for attr, value in six.iteritems(doc) if value is not None} return cls(**attrs)
def from_model(cls, model, mask_secrets=True): if not KeyValuePairAPI.crypto_setup: KeyValuePairAPI._setup_crypto() doc = cls._from_model(model, mask_secrets=mask_secrets) if getattr(model, "expire_timestamp", None) and model.expire_timestamp: doc["expire_timestamp"] = isotime.format(model.expire_timestamp, offset=False) encrypted = False secret = getattr(model, "secret", False) if secret: encrypted = True if not mask_secrets and secret: doc["value"] = symmetric_decrypt(KeyValuePairAPI.crypto_key, model.value) encrypted = False scope = getattr(model, "scope", SYSTEM_SCOPE) if scope: doc["scope"] = scope key = doc.get("name", None) if (scope == USER_SCOPE or scope == FULL_USER_SCOPE) and key: doc["user"] = UserKeyReference.get_user(key) doc["name"] = UserKeyReference.get_name(key) doc["encrypted"] = encrypted attrs = { attr: value for attr, value in six.iteritems(doc) if value is not None } return cls(**attrs)
def decrypt_kv(value): original_value = value if isinstance(value, KeyValueLookup) or isinstance(value, UserKeyValueLookup): # Since this is a filter the incoming value is still a KeyValueLookup # object as the jinja rendering is not yet complete. So we cast # the KeyValueLookup object to a simple string before decrypting. is_kv_item = True value = str(value) else: is_kv_item = False # NOTE: If value is None this indicate key value item doesn't exist and we hrow a more # user-friendly error if is_kv_item and value == '': # Build original key name key_name = original_value.get_key_name() raise ValueError( 'Referenced datastore item "%s" doesn\'t exist or it contains an empty ' 'string' % (key_name)) crypto_key_path = cfg.CONF.keyvalue.encryption_key_path crypto_key = read_crypto_key(key_path=crypto_key_path) return symmetric_decrypt(decrypt_key=crypto_key, ciphertext=value)
def from_model(cls, model, mask_secrets=True): if not KeyValuePairAPI.crypto_setup: KeyValuePairAPI._setup_crypto() doc = cls._from_model(model, mask_secrets=mask_secrets) if getattr(model, 'expire_timestamp', None) and model.expire_timestamp: doc['expire_timestamp'] = isotime.format(model.expire_timestamp, offset=False) encrypted = False secret = getattr(model, 'secret', False) if secret: encrypted = True if not mask_secrets and secret: doc['value'] = symmetric_decrypt(KeyValuePairAPI.crypto_key, model.value) encrypted = False scope = getattr(model, 'scope', SYSTEM_SCOPE) if scope: doc['scope'] = scope key = doc.get('name', None) if (scope == USER_SCOPE or scope == FULL_USER_SCOPE) and key: doc['user'] = UserKeyReference.get_user(key) doc['name'] = UserKeyReference.get_name(key) doc['encrypted'] = encrypted attrs = {attr: value for attr, value in six.iteritems(doc) if value is not None} return cls(**attrs)
def decrypt_kv(value): if isinstance(value, KeyValueLookup): # Since this is a filter the incoming value is still a KeyValueLookup # object as the jinja rendering is not yet complete. So we cast # the KeyValueLookup object to a simple string before decrypting. value = str(value) crypto_key_path = cfg.CONF.keyvalue.encryption_key_path crypto_key = read_crypto_key(key_path=crypto_key_path) return symmetric_decrypt(decrypt_key=crypto_key, ciphertext=value)
def test_symmetric_encrypt_decrypt_utf8_character(self): values = [ u'£', u'£££', u'££££££', u'č š hello đ č p ž Ž', u'hello 💩', u'💩💩💩💩💩' u'💩💩💩', u'💩😁' ] for index, original in enumerate(values): crypto = symmetric_encrypt(CryptoUtilsTestCase.test_crypto_key, original) plain = symmetric_decrypt(CryptoUtilsTestCase.test_crypto_key, crypto) self.assertEqual(plain, original) self.assertEqual(index, (len(values) - 1))
def deserialize_key_value(value, secret=False): """ Deserialize the datastore item value. Note: Right now only strings as supported so only thing this function does is it decrypts secret values. :param value: Value to deserialize. :type value: ``str`` :param secret: True if a value is a secret and is encrypted. :type secret: ``bool`` """ if secret: KeyValuePairAPI._setup_crypto() value = symmetric_decrypt(KeyValuePairAPI.crypto_key, value) return value
def decrypt_kv(value): original_value = value if isinstance(value, KeyValueLookup) or isinstance(value, UserKeyValueLookup): # Since this is a filter the incoming value is still a KeyValueLookup # object as the jinja rendering is not yet complete. So we cast # the KeyValueLookup object to a simple string before decrypting. is_kv_item = True value = str(value) else: is_kv_item = False # NOTE: If value is None this indicate key value item doesn't exist and we hrow a more # user-friendly error if is_kv_item and value == '': # Build original key name key_name = original_value.get_key_name() raise ValueError('Referenced datastore item "%s" doesn\'t exist or it contains an empty ' 'string' % (key_name)) crypto_key_path = cfg.CONF.keyvalue.encryption_key_path crypto_key = read_crypto_key(key_path=crypto_key_path) return symmetric_decrypt(decrypt_key=crypto_key, ciphertext=value)
def from_model(cls, model, mask_secrets=True): if not KeyValuePairAPI.crypto_setup: KeyValuePairAPI._setup_crypto() doc = cls._from_model(model, mask_secrets=mask_secrets) if 'id' in doc: del doc['id'] if model.expire_timestamp: doc['expire_timestamp'] = isotime.format(model.expire_timestamp, offset=False) encrypted = False if model.secret: encrypted = True if not mask_secrets and model.secret: doc['value'] = symmetric_decrypt(KeyValuePairAPI.crypto_key, model.value) encrypted = False doc['encrypted'] = encrypted attrs = {attr: value for attr, value in six.iteritems(doc) if value is not None} return cls(**attrs)
def to_model(cls, kvp): if not KeyValuePairAPI.crypto_setup: KeyValuePairAPI._setup_crypto() kvp_id = getattr(kvp, 'id', None) name = getattr(kvp, 'name', None) description = getattr(kvp, 'description', None) value = kvp.value original_value = value secret = False if getattr(kvp, 'ttl', None): expire_timestamp = (date_utils.get_datetime_utc_now() + datetime.timedelta(seconds=kvp.ttl)) else: expire_timestamp = None encrypted = getattr(kvp, 'encrypted', False) secret = getattr(kvp, 'secret', False) # If user transmitted the value in an pre-encrypted format, we perform the decryption here # to ensure data integrity. Besides that, we store data as-is. # Keep in mind that encrypted=True also always implies secret=True. If we didn't do # that and supported encrypted=True, secret=False, this would allow users to decrypt # any encrypted value. if encrypted: secret = True cls._verif_key_is_set_up(name=name) try: symmetric_decrypt(KeyValuePairAPI.crypto_key, value) except Exception: msg = ('Failed to verify the integrity of the provided value for key "%s". Ensure ' 'that the value is encrypted with the correct key and not corrupted.' % (name)) raise ValueError(msg) # Additional safety check to ensure that the value hasn't been decrypted assert value == original_value elif secret: cls._verif_key_is_set_up(name=name) value = symmetric_encrypt(KeyValuePairAPI.crypto_key, value) scope = getattr(kvp, 'scope', FULL_SYSTEM_SCOPE) if scope not in ALLOWED_SCOPES: raise InvalidScopeException('Invalid scope "%s"! Allowed scopes are %s.' % ( scope, ALLOWED_SCOPES) ) # NOTE: For security reasons, encrypted always implies secret=True. See comment # above for explanation. if encrypted and not secret: raise ValueError('encrypted option can only be used in combination with secret ' 'option') model = cls.model(id=kvp_id, name=name, description=description, value=value, secret=secret, scope=scope, expire_timestamp=expire_timestamp) return model
def test_symmetric_encrypt_decrypt_short_string_needs_to_be_padded(self): original = u'a' crypto = symmetric_encrypt(CryptoUtilsTestCase.test_crypto_key, original) plain = symmetric_decrypt(CryptoUtilsTestCase.test_crypto_key, crypto) self.assertEqual(plain, original)
def test_symmetric_encrypt_decrypt(self): original = 'secret' crypto = crypto_utils.symmetric_encrypt(CryptoUtilsTestCase.test_crypto_key, original) plain = crypto_utils.symmetric_decrypt(CryptoUtilsTestCase.test_crypto_key, crypto) self.assertEqual(plain, original)
def to_model(cls, kvp): if not KeyValuePairAPI.crypto_setup: KeyValuePairAPI._setup_crypto() kvp_id = getattr(kvp, "id", None) name = getattr(kvp, "name", None) description = getattr(kvp, "description", None) value = kvp.value original_value = value secret = False if getattr(kvp, "ttl", None): expire_timestamp = date_utils.get_datetime_utc_now( ) + datetime.timedelta(seconds=kvp.ttl) else: expire_timestamp = None encrypted = getattr(kvp, "encrypted", False) secret = getattr(kvp, "secret", False) # If user transmitted the value in an pre-encrypted format, we perform the decryption here # to ensure data integrity. Besides that, we store data as-is. # Keep in mind that encrypted=True also always implies secret=True. If we didn't do # that and supported encrypted=True, secret=False, this would allow users to decrypt # any encrypted value. if encrypted: secret = True cls._verif_key_is_set_up(name=name) try: symmetric_decrypt(KeyValuePairAPI.crypto_key, value) except Exception: msg = ( 'Failed to verify the integrity of the provided value for key "%s". Ensure ' "that the value is encrypted with the correct key and not corrupted." % (name)) raise ValueError(msg) # Additional safety check to ensure that the value hasn't been decrypted if value != original_value: raise ValueError( f"The encrypted value {value} is not the" f" same original encrypted value {original_value}.") elif secret: cls._verif_key_is_set_up(name=name) value = symmetric_encrypt(KeyValuePairAPI.crypto_key, value) scope = getattr(kvp, "scope", FULL_SYSTEM_SCOPE) if scope not in ALLOWED_SCOPES: raise InvalidScopeException( 'Invalid scope "%s"! Allowed scopes are %s.' % (scope, ALLOWED_SCOPES)) # NOTE: For security reasons, encrypted always implies secret=True. See comment # above for explanation. if encrypted and not secret: raise ValueError( "encrypted option can only be used in combination with secret " "option") model = cls.model( id=kvp_id, name=name, description=description, value=value, secret=secret, scope=scope, expire_timestamp=expire_timestamp, ) return model