diff --git a/cinder/volume/drivers/synology/synology_common.py b/cinder/volume/drivers/synology/synology_common.py index 1a591a519dd..b982d72ed00 100644 --- a/cinder/volume/drivers/synology/synology_common.py +++ b/cinder/volume/drivers/synology/synology_common.py @@ -18,13 +18,17 @@ import functools import hashlib import json import math +from os import urandom from random import randint import string -from Crypto.Cipher import AES -from Crypto.Cipher import PKCS1_v1_5 -from Crypto.PublicKey import RSA -from Crypto import Random +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.ciphers import algorithms +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers import modes +from cryptography.hazmat.primitives import hashes import eventlet from oslo_config import cfg from oslo_log import log as logging @@ -84,8 +88,8 @@ class AESCipher(object): SALT_MAGIC = 'Salted__' def __init__(self, password, key_length=32): - self._bs = AES.block_size - self._salt = Random.new().read(self._bs - len(self.SALT_MAGIC)) + self._bs = 16 + self._salt = urandom(self._bs - len(self.SALT_MAGIC)) self._key, self._iv = self._derive_key_and_iv(password, self._salt, @@ -105,8 +109,13 @@ class AESCipher(object): return d[:key_length], d[key_length:key_length + iv_length] def encrypt(self, text): - cipher = AES.new(self._key, AES.MODE_CBC, self._iv) - ciphertext = cipher.encrypt(self._pad(text)) + cipher = Cipher( + algorithms.AES(self._key), + modes.CBC(self._iv), + backend = default_backend() + ) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(self._pad(text)) + encryptor.finalize() return "%s%s%s" % (self.SALT_MAGIC, self._salt, ciphertext) @@ -165,7 +174,7 @@ class Session(object): else: raise exception.SynoAuthError(reason=_('Login failed.')) - def _random_AES_passpharse(self, length): + def _random_AES_passphrase(self, length): available = ('0123456789' 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -191,9 +200,20 @@ class Session(object): return result["data"] def _encrypt_RSA(self, modulus, passphrase, text): - key = RSA.construct((modulus, passphrase)) - cipher = PKCS1_v1_5.new(key) - ciphertext = cipher.encrypt(text) + key = rsa.generate_private_key( + key_size = modulus, + public_exponent = passphrase, + backend = default_backend() + ) + public_key = key.public_key() + + ciphertext = public_key.encrypt( + text, + padding.PKCS1v15( + mgf = padding.PKCS1v15(algorithm = hashes.SHA1()), + algorithm = hashes.SHA1() + ) + ) return ciphertext @@ -208,7 +228,7 @@ class Session(object): cipher_key = enc_info["cipherkey"] cipher_token = enc_info["ciphertoken"] server_time = enc_info["server_time"] - random_passphrase = self._random_AES_passpharse(501) + random_passphrase = self._random_AES_passphrase(501) params[cipher_token] = server_time diff --git a/cinder/volume/utils.py b/cinder/volume/utils.py index a84d5ef317a..dc4752f7d8d 100644 --- a/cinder/volume/utils.py +++ b/cinder/volume/utils.py @@ -19,11 +19,11 @@ import ast import functools import math import operator +from os import urandom import re import time import uuid -from Crypto.Random import random import eventlet from eventlet import tpool from oslo_concurrency import processutils @@ -32,6 +32,7 @@ from oslo_log import log as logging from oslo_utils import strutils from oslo_utils import timeutils from oslo_utils import units +from random import shuffle import six from six.moves import range @@ -652,21 +653,27 @@ def generate_password(length=16, symbolgroups=DEFAULT_PASSWORD_SYMBOLS): # NOTE(jerdfelt): Some password policies require at least one character # from each group of symbols, so start off with one random character # from each symbol group - password = [random.choice(s) for s in symbolgroups] + + bytes = 1 # Number of random bytes to generate for each choice + + password = [s[ord(urandom(bytes)) % len(s)] + for s in symbolgroups] # If length < len(symbolgroups), the leading characters will only # be from the first length groups. Try our best to not be predictable # by shuffling and then truncating. - random.shuffle(password) + shuffle(password) password = password[:length] length -= len(password) # then fill with random characters from all symbol groups symbols = ''.join(symbolgroups) - password.extend([random.choice(symbols) for _i in range(length)]) + password.extend( + [symbols[ord(urandom(bytes)) % len(symbols)] + for _i in range(length)]) # finally shuffle to ensure first x characters aren't from a # predictable group - random.shuffle(password) + shuffle(password) return ''.join(password) diff --git a/requirements.txt b/requirements.txt index 38551099a08..0b3af0a8274 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,7 +35,6 @@ paramiko>=2.0 # LGPLv2.1+ Paste # MIT PasteDeploy>=1.5.0 # MIT psutil>=3.2.2 # BSD -pycrypto>=2.6 # Public Domain pyparsing>=2.1.0 # MIT python-barbicanclient>=4.0.0 # Apache-2.0 python-glanceclient>=2.5.0 # Apache-2.0 @@ -63,3 +62,4 @@ os-win>=2.0.0 # Apache-2.0 tooz>=1.47.0 # Apache-2.0 google-api-python-client>=1.4.2 # Apache-2.0 castellan>=0.7.0 # Apache-2.0 +cryptography>=1.6 # BSD/Apache-2.0