Remove oslo-incubator modules
Oslo.incubator has become a history. This patch moves the crypto utils functions to heat.common.crypt. This also cleans up crypt.py to remove some unused methods. Co-Authored-By: Rabi Mishra <ramishra@redhat.com> Change-Id: I439612b37249f0cca041361e647e36643150c3d6
This commit is contained in:
parent
77939dc9cb
commit
0f2f9c2155
@ -18,9 +18,9 @@ from Crypto.Cipher import AES
|
||||
from cryptography import fernet
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import importutils
|
||||
|
||||
from heat.common.i18n import _
|
||||
from heat.openstack.common.crypto import utils
|
||||
|
||||
auth_opts = [
|
||||
cfg.StrOpt('auth_encryption_key',
|
||||
@ -33,6 +33,46 @@ auth_opts = [
|
||||
cfg.CONF.register_opts(auth_opts)
|
||||
|
||||
|
||||
class SymmetricCrypto(object):
|
||||
"""Symmetric Key Crypto object.
|
||||
|
||||
This class creates a Symmetric Key Crypto object that can be used
|
||||
to decrypt arbitrary data.
|
||||
|
||||
Note: This is moved here from oslo-incubator for backward
|
||||
compatibility. Once we've db migration script available to
|
||||
re-rencrypt using new encryption method as part of upgrade,
|
||||
this can be removed.
|
||||
|
||||
:param enctype: Encryption Cipher name (default: AES)
|
||||
"""
|
||||
|
||||
def __init__(self, enctype='AES'):
|
||||
self.cipher = importutils.import_module('Crypto.Cipher.' + enctype)
|
||||
|
||||
def decrypt(self, key, msg, b64decode=True):
|
||||
"""Decrypts the provided ciphertext.
|
||||
|
||||
The ciphertext can be optionally base64 encoded.
|
||||
|
||||
Uses AES-128-CBC with an IV by default.
|
||||
|
||||
:param key: The Encryption key.
|
||||
:param msg: the ciphetext, the first block is the IV
|
||||
|
||||
:returns plain: the plaintext message, after padding is removed.
|
||||
"""
|
||||
if b64decode:
|
||||
msg = base64.b64decode(msg)
|
||||
iv = msg[:self.cipher.block_size]
|
||||
cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv)
|
||||
|
||||
padded = cipher.decrypt(msg[self.cipher.block_size:])
|
||||
l = ord(padded[-1:]) + 1
|
||||
plain = padded[:-l]
|
||||
return plain
|
||||
|
||||
|
||||
def encrypt(value, encryption_key=None):
|
||||
if value is None:
|
||||
return None, None
|
||||
@ -54,9 +94,8 @@ def decrypt(method, data, encryption_key=None):
|
||||
|
||||
def oslo_decrypt_v1(value, encryption_key=None):
|
||||
encryption_key = get_valid_encryption_key(encryption_key)
|
||||
sym = utils.SymmetricCrypto()
|
||||
return sym.decrypt(encryption_key,
|
||||
value, b64decode=True)
|
||||
sym = SymmetricCrypto()
|
||||
return sym.decrypt(encryption_key, value, b64decode=True)
|
||||
|
||||
|
||||
def cryptography_decrypt_v1(value, encryption_key=None):
|
||||
|
@ -1,16 +0,0 @@
|
||||
oslo-incubator
|
||||
--------------
|
||||
|
||||
A number of modules from oslo-incubator are imported into this project.
|
||||
You can clone the oslo-incubator repository using the following url:
|
||||
|
||||
https://git.openstack.org/openstack/oslo-incubator
|
||||
|
||||
These modules are "incubating" in oslo-incubator and are kept in sync
|
||||
with the help of oslo-incubator's update.py script. See:
|
||||
|
||||
https://wiki.openstack.org/wiki/Oslo#Syncing_Code_from_Incubator
|
||||
|
||||
The copy of the code should never be directly modified here. Please
|
||||
always update oslo-incubator first and then run the script to copy
|
||||
the changes across.
|
@ -1,45 +0,0 @@
|
||||
# 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.
|
||||
|
||||
"""oslo.i18n integration module.
|
||||
|
||||
See http://docs.openstack.org/developer/oslo.i18n/usage.html
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
import oslo_i18n
|
||||
|
||||
# NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
|
||||
# application name when this module is synced into the separate
|
||||
# repository. It is OK to have more than one translation function
|
||||
# using the same domain, since there will still only be one message
|
||||
# catalog.
|
||||
_translators = oslo_i18n.TranslatorFactory(domain='heat')
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
||||
|
||||
# Translators for log levels.
|
||||
#
|
||||
# The abbreviated names are meant to reflect the usual use of a short
|
||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
||||
# the level.
|
||||
_LI = _translators.log_info
|
||||
_LW = _translators.log_warning
|
||||
_LE = _translators.log_error
|
||||
_LC = _translators.log_critical
|
||||
except ImportError:
|
||||
# NOTE(dims): Support for cases where a project wants to use
|
||||
# code from oslo-incubator, but is not ready to be internationalized
|
||||
# (like tempest)
|
||||
_ = _LI = _LW = _LE = _LC = lambda x: x
|
@ -1,198 +0,0 @@
|
||||
# Copyright 2013 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# THIS MODULE IS DEPRECATED
|
||||
#
|
||||
# Please refer to
|
||||
# https://etherpad.openstack.org/p/kilo-heat-library-proposals for
|
||||
# the discussion leading to this deprecation.
|
||||
#
|
||||
# We recommend checking out Barbican or the cryptography.py project
|
||||
# (https://pypi.python.org/pypi/cryptography) instead of this module.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
import base64
|
||||
|
||||
from Crypto import Hash
|
||||
from Crypto import Random
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from heat.openstack.common._i18n import _
|
||||
|
||||
bchr = six.int2byte
|
||||
|
||||
|
||||
class CryptoutilsException(Exception):
|
||||
"""Generic Exception for Crypto utilities."""
|
||||
|
||||
message = _("An unknown error occurred in crypto utils.")
|
||||
|
||||
|
||||
class CipherBlockLengthTooBig(CryptoutilsException):
|
||||
"""The block size is too big."""
|
||||
|
||||
def __init__(self, requested, permitted):
|
||||
msg = _("Block size of %(given)d is too big, max = %(maximum)d")
|
||||
message = msg % {'given': requested, 'maximum': permitted}
|
||||
super(CryptoutilsException, self).__init__(message)
|
||||
|
||||
|
||||
class HKDFOutputLengthTooLong(CryptoutilsException):
|
||||
"""The amount of Key Material asked is too much."""
|
||||
|
||||
def __init__(self, requested, permitted):
|
||||
msg = _("Length of %(given)d is too long, max = %(maximum)d")
|
||||
message = msg % {'given': requested, 'maximum': permitted}
|
||||
super(CryptoutilsException, self).__init__(message)
|
||||
|
||||
|
||||
class HKDF(object):
|
||||
"""An HMAC-based Key Derivation Function implementation (RFC5869)
|
||||
|
||||
This class creates an object that allows to use HKDF to derive keys.
|
||||
"""
|
||||
|
||||
def __init__(self, hashtype='SHA256'):
|
||||
self.hashfn = importutils.import_module('Crypto.Hash.' + hashtype)
|
||||
self.max_okm_length = 255 * self.hashfn.digest_size
|
||||
|
||||
def extract(self, ikm, salt=None):
|
||||
"""An extract function that can be used to derive a robust key given
|
||||
weak Input Key Material (IKM) which could be a password.
|
||||
Returns a pseudorandom key (of HashLen octets)
|
||||
|
||||
:param ikm: input keying material (ex a password)
|
||||
:param salt: optional salt value (a non-secret random value)
|
||||
"""
|
||||
if salt is None:
|
||||
salt = b'\x00' * self.hashfn.digest_size
|
||||
|
||||
return Hash.HMAC.new(salt, ikm, self.hashfn).digest()
|
||||
|
||||
def expand(self, prk, info, length):
|
||||
"""An expand function that will return arbitrary length output that can
|
||||
be used as keys.
|
||||
Returns a buffer usable as key material.
|
||||
|
||||
:param prk: a pseudorandom key of at least HashLen octets
|
||||
:param info: optional string (can be a zero-length string)
|
||||
:param length: length of output keying material (<= 255 * HashLen)
|
||||
"""
|
||||
if length > self.max_okm_length:
|
||||
raise HKDFOutputLengthTooLong(length, self.max_okm_length)
|
||||
|
||||
N = (length + self.hashfn.digest_size - 1) // self.hashfn.digest_size
|
||||
|
||||
okm = b""
|
||||
tmp = b""
|
||||
for block in range(1, N + 1):
|
||||
tmp = Hash.HMAC.new(
|
||||
prk, tmp + info + bchr(block), self.hashfn).digest()
|
||||
okm += tmp
|
||||
|
||||
return okm[:length]
|
||||
|
||||
|
||||
MAX_CB_SIZE = 256
|
||||
|
||||
|
||||
class SymmetricCrypto(object):
|
||||
"""Symmetric Key Crypto object.
|
||||
|
||||
This class creates a Symmetric Key Crypto object that can be used
|
||||
to encrypt, decrypt, or sign arbitrary data.
|
||||
|
||||
:param enctype: Encryption Cipher name (default: AES)
|
||||
:param hashtype: Hash/HMAC type name (default: SHA256)
|
||||
"""
|
||||
|
||||
def __init__(self, enctype='AES', hashtype='SHA256'):
|
||||
self.cipher = importutils.import_module('Crypto.Cipher.' + enctype)
|
||||
self.hashfn = importutils.import_module('Crypto.Hash.' + hashtype)
|
||||
|
||||
def new_key(self, size):
|
||||
return Random.new().read(size)
|
||||
|
||||
def encrypt(self, key, msg, b64encode=True):
|
||||
"""Encrypt the provided msg and returns the cyphertext optionally
|
||||
base64 encoded.
|
||||
|
||||
Uses AES-128-CBC with a Random IV by default.
|
||||
|
||||
The plaintext is padded to reach blocksize length.
|
||||
The last byte of the block is the length of the padding.
|
||||
The length of the padding does not include the length byte itself.
|
||||
|
||||
:param key: The Encryption key.
|
||||
:param msg: the plain text.
|
||||
|
||||
:returns enc: a block of encrypted data.
|
||||
"""
|
||||
iv = Random.new().read(self.cipher.block_size)
|
||||
cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv)
|
||||
|
||||
# CBC mode requires a fixed block size. Append padding and length of
|
||||
# padding.
|
||||
if self.cipher.block_size > MAX_CB_SIZE:
|
||||
raise CipherBlockLengthTooBig(self.cipher.block_size, MAX_CB_SIZE)
|
||||
r = len(msg) % self.cipher.block_size
|
||||
padlen = self.cipher.block_size - r - 1
|
||||
msg += b'\x00' * padlen
|
||||
msg += bchr(padlen)
|
||||
|
||||
enc = iv + cipher.encrypt(msg)
|
||||
if b64encode:
|
||||
enc = base64.b64encode(enc)
|
||||
return enc
|
||||
|
||||
def decrypt(self, key, msg, b64decode=True):
|
||||
"""Decrypts the provided ciphertext, optionally base64 encoded, and
|
||||
returns the plaintext message, after padding is removed.
|
||||
|
||||
Uses AES-128-CBC with an IV by default.
|
||||
|
||||
:param key: The Encryption key.
|
||||
:param msg: the ciphetext, the first block is the IV
|
||||
|
||||
:returns plain: the plaintext message.
|
||||
"""
|
||||
if b64decode:
|
||||
msg = base64.b64decode(msg)
|
||||
iv = msg[:self.cipher.block_size]
|
||||
cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv)
|
||||
|
||||
padded = cipher.decrypt(msg[self.cipher.block_size:])
|
||||
l = ord(padded[-1:]) + 1
|
||||
plain = padded[:-l]
|
||||
return plain
|
||||
|
||||
def sign(self, key, msg, b64encode=True):
|
||||
"""Signs a message string and returns a base64 encoded signature.
|
||||
|
||||
Uses HMAC-SHA-256 by default.
|
||||
|
||||
:param key: The Signing key.
|
||||
:param msg: the message to sign.
|
||||
|
||||
:returns out: a base64 encoded signature.
|
||||
"""
|
||||
h = Hash.HMAC.new(key, msg, self.hashfn)
|
||||
out = h.digest()
|
||||
if b64encode:
|
||||
out = base64.b64encode(out)
|
||||
return out
|
@ -1,7 +0,0 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from oslo-incubator
|
||||
module=crypto
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=heat
|
@ -51,7 +51,6 @@ oslo.config.opts =
|
||||
heat.engine.clients = heat.engine.clients:list_opts
|
||||
heat.engine.notification = heat.engine.notification:list_opts
|
||||
heat.engine.resources = heat.engine.resources:list_opts
|
||||
heat.openstack.common.policy = heat.openstack.common.policy:list_opts
|
||||
heat.api.middleware.ssl = heat.api.middleware.ssl:list_opts
|
||||
heat.api.aws.ec2token = heat.api.aws.ec2token:list_opts
|
||||
heat_integrationtests.common.config = heat_integrationtests.common.config:list_opts
|
||||
@ -192,7 +191,6 @@ autodoc_exclude_modules =
|
||||
heat.db.*
|
||||
heat.engine.resources.*
|
||||
heat.locale.*
|
||||
heat.openstack.*
|
||||
*.tests.*
|
||||
*.resources.*
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user