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:
tengqm 2016-03-24 21:56:41 -04:00 committed by rabi
parent 77939dc9cb
commit 0f2f9c2155
9 changed files with 43 additions and 272 deletions

View File

@ -18,9 +18,9 @@ from Crypto.Cipher import AES
from cryptography import fernet from cryptography import fernet
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import encodeutils from oslo_utils import encodeutils
from oslo_utils import importutils
from heat.common.i18n import _ from heat.common.i18n import _
from heat.openstack.common.crypto import utils
auth_opts = [ auth_opts = [
cfg.StrOpt('auth_encryption_key', cfg.StrOpt('auth_encryption_key',
@ -33,6 +33,46 @@ auth_opts = [
cfg.CONF.register_opts(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): def encrypt(value, encryption_key=None):
if value is None: if value is None:
return None, None return None, None
@ -54,9 +94,8 @@ def decrypt(method, data, encryption_key=None):
def oslo_decrypt_v1(value, encryption_key=None): def oslo_decrypt_v1(value, encryption_key=None):
encryption_key = get_valid_encryption_key(encryption_key) encryption_key = get_valid_encryption_key(encryption_key)
sym = utils.SymmetricCrypto() sym = SymmetricCrypto()
return sym.decrypt(encryption_key, return sym.decrypt(encryption_key, value, b64decode=True)
value, b64decode=True)
def cryptography_decrypt_v1(value, encryption_key=None): def cryptography_decrypt_v1(value, encryption_key=None):

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -51,7 +51,6 @@ oslo.config.opts =
heat.engine.clients = heat.engine.clients:list_opts heat.engine.clients = heat.engine.clients:list_opts
heat.engine.notification = heat.engine.notification:list_opts heat.engine.notification = heat.engine.notification:list_opts
heat.engine.resources = heat.engine.resources: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.middleware.ssl = heat.api.middleware.ssl:list_opts
heat.api.aws.ec2token = heat.api.aws.ec2token:list_opts heat.api.aws.ec2token = heat.api.aws.ec2token:list_opts
heat_integrationtests.common.config = heat_integrationtests.common.config:list_opts heat_integrationtests.common.config = heat_integrationtests.common.config:list_opts
@ -192,7 +191,6 @@ autodoc_exclude_modules =
heat.db.* heat.db.*
heat.engine.resources.* heat.engine.resources.*
heat.locale.* heat.locale.*
heat.openstack.*
*.tests.* *.tests.*
*.resources.* *.resources.*