From fd7fd762742a2a6d45c42349d8f196fee398dd6b Mon Sep 17 00:00:00 2001 From: Ilya Etingof Date: Thu, 17 May 2018 11:35:55 +0200 Subject: [PATCH] Migrate from PyCrypto to Cryptography The King is dead, long live the King! Change-Id: I2491c2b7e4aebcb9122a16918a2a35caaa580e38 Story: 2002056 Task: 19705 --- lower-constraints.txt | 2 +- pyghmi/ipmi/private/session.py | 37 +++++++++++++++++++++++----------- requirements.txt | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lower-constraints.txt b/lower-constraints.txt index 17cb06db..85549d7f 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -1,8 +1,8 @@ coverage===4.0 +cryptography===2.1 fixtures===3.0.0 oslotest===3.2.0 os-testr===1.0.0 -pycrypto===2.6 python-subunit===1.0.0 Sphinx===1.6.5 testrepository===0.0.18 diff --git a/pyghmi/ipmi/private/session.py b/pyghmi/ipmi/private/session.py index fc1d46cb..2988e570 100644 --- a/pyghmi/ipmi/private/session.py +++ b/pyghmi/ipmi/private/session.py @@ -27,10 +27,9 @@ import socket import struct import threading -try: - from Cryptodome.Cipher import AES -except ImportError: - from Crypto.Cipher import AES + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes import pyghmi.exceptions as exc from pyghmi.ipmi.private import constants @@ -305,6 +304,10 @@ class Session(object): # can do something like reassign our threading and select modules socketchecking = None + # Maintain single Cryptography backend for all IPMI sessions (seems to be + # thread-safe) + _crypto_backend = default_backend() + @classmethod def _cleanup(cls): for sesskey in list(cls.bmc_handlers): @@ -872,10 +875,15 @@ class Session(object): iv = os.urandom(16) message += list(struct.unpack("16B", iv)) payloadtocrypt = _aespad(payload) - crypter = AES.new(self.aeskey, AES.MODE_CBC, iv) - crypted = crypter.encrypt(struct.pack("%dB" % - len(payloadtocrypt), - *payloadtocrypt)) + crypter = Cipher( + algorithm=algorithms.AES(self.aeskey), + mode=modes.CBC(iv), + backend=self._crypto_backend + ) + encryptor = crypter.encryptor() + plaintext = struct.pack("%dB" % len(payloadtocrypt), + *payloadtocrypt) + crypted = encryptor.update(plaintext) + encryptor.finalize() crypted = list(struct.unpack("%dB" % len(crypted), crypted)) message += crypted else: # no confidetiality algorithm @@ -1378,10 +1386,15 @@ class Session(object): payload = data[16:16 + psize] if encrypted: iv = data[16:32] - decrypter = AES.new(self.aeskey, AES.MODE_CBC, bytes(iv)) - decrypted = decrypter.decrypt( - struct.pack("%dB" % len(payload[16:]), - *payload[16:])) + crypter = Cipher( + algorithm=algorithms.AES(self.aeskey), + mode=modes.CBC(bytes(iv)), + backend=self._crypto_backend + ) + decryptor = crypter.decryptor() + ciphertext = struct.pack("%dB" % len(payload[16:]), + *payload[16:]) + decrypted = decryptor.update(ciphertext) + decryptor.finalize() payload = struct.unpack("%dB" % len(decrypted), decrypted) padsize = payload[-1] + 1 payload = list(payload[:-padsize]) diff --git a/requirements.txt b/requirements.txt index ae8cd06a..c010a524 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pycrypto>=2.6 +cryptography!=2.0 # BSD/Apache-2.0