
For some use cases operators would like to periodically introduce a new encryption root secret that would be used when new object data is written. However, existing encrypted data does not need to be re-encrypted with keys derived from the new root secret. Older root secret(s) would still be used as necessary to decrypt older object data. This patch modifies the KeyMaster class to support multiple root secrets indexed via unique secret_id's, and to store the id of the root secret used for an encryption operation in the crypto meta. The decrypter is modified to fetch appropriate keys based on the secret id in retrieved crypto meta. The changes are backwards compatible with previous crypto middleware configurations and existing encrypted object data. Change-Id: I40307acf39b6c1cc9921f711a8da55d03924d232
74 lines
2.5 KiB
Python
74 lines
2.5 KiB
Python
# Copyright (c) 2015-2016 OpenStack Foundation
|
|
#
|
|
# 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 base64
|
|
import hashlib
|
|
|
|
from swift.common.exceptions import UnknownSecretIdError
|
|
from swift.common.middleware.crypto.crypto_utils import Crypto
|
|
|
|
|
|
def fetch_crypto_keys(key_id=None):
|
|
id_to_keys = {None: {'account': 'This is an account key 012345678',
|
|
'container': 'This is a container key 01234567',
|
|
'object': 'This is an object key 0123456789'},
|
|
'myid': {'account': 'This is an account key 123456789',
|
|
'container': 'This is a container key 12345678',
|
|
'object': 'This is an object key 1234567890'}}
|
|
key_id = key_id or {}
|
|
secret_id = key_id.get('secret_id') or None
|
|
try:
|
|
keys = dict(id_to_keys[secret_id])
|
|
except KeyError:
|
|
raise UnknownSecretIdError(secret_id)
|
|
keys['id'] = {'v': 'fake', 'path': '/a/c/fake'}
|
|
if secret_id:
|
|
keys['id']['secret_id'] = secret_id
|
|
keys['all_ids'] = [{'v': 'fake', 'path': '/a/c/fake'},
|
|
{'v': 'fake', 'path': '/a/c/fake', 'secret_id': 'myid'}]
|
|
return keys
|
|
|
|
|
|
def md5hex(s):
|
|
return hashlib.md5(s).hexdigest()
|
|
|
|
|
|
def encrypt(val, key=None, iv=None, ctxt=None):
|
|
if ctxt is None:
|
|
ctxt = Crypto({}).create_encryption_ctxt(key, iv)
|
|
enc_val = ctxt.update(val)
|
|
return enc_val
|
|
|
|
|
|
def decrypt(key, iv, enc_val):
|
|
dec_ctxt = Crypto({}).create_decryption_ctxt(key, iv, 0)
|
|
dec_val = dec_ctxt.update(enc_val)
|
|
return dec_val
|
|
|
|
|
|
FAKE_IV = "This is an IV123"
|
|
# do not use this example encryption_root_secret in production, use a randomly
|
|
# generated value with high entropy
|
|
TEST_KEYMASTER_CONF = {
|
|
'encryption_root_secret': base64.b64encode(b'x' * 32),
|
|
'encryption_root_secret_1': base64.b64encode(b'y' * 32),
|
|
'encryption_root_secret_2': base64.b64encode(b'z' * 32)
|
|
}
|
|
|
|
|
|
def fake_get_crypto_meta(**kwargs):
|
|
meta = {'iv': FAKE_IV, 'cipher': Crypto.cipher}
|
|
meta.update(kwargs)
|
|
return meta
|