Use cryptography instead of pycrypto

pycrypto is no longer maintained [1]. This patch rewrites functions
using pycrypto and replaces them with the cryptography equivalent

[1] http://lists.openstack.org/pipermail/openstack-dev/2017-March/113568.html

Change-Id: I438fdbb76ceb7edf23bc5640596ed64feb59aa46
This commit is contained in:
Nicholas Jones 2017-03-31 15:26:19 -05:00
parent f1dfad4618
commit 1d0a36d28c
3 changed files with 46 additions and 19 deletions

View File

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

View File

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

View File

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