Switch to cryptograhy for crypto routines

This commit is contained in:
Pierre Ståhl
2020-09-26 22:53:24 +02:00
committed by rospogrigio
parent 2879761eae
commit b7173f3033
4 changed files with 17 additions and 51 deletions

View File

@@ -9,7 +9,8 @@ import asyncio
import logging import logging
from hashlib import md5 from hashlib import md5
from Cryptodome.Cipher import AES from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -22,7 +23,9 @@ def decrypt_udp(message):
def _unpad(data): def _unpad(data):
return data[: -ord(data[len(data) - 1 :])] return data[: -ord(data[len(data) - 1 :])]
return _unpad(AES.new(UDP_KEY, AES.MODE_ECB).decrypt(message)).decode() cipher = Cipher(algorithms.AES(UDP_KEY), modes.ECB(), default_backend())
decryptor = cipher.decryptor()
return _unpad(decryptor.update(message) + decryptor.finalize()).decode()
class TuyaDiscovery(asyncio.DatagramProtocol): class TuyaDiscovery(asyncio.DatagramProtocol):

View File

@@ -6,6 +6,6 @@
"codeowners": [ "codeowners": [
"@rospogrigio" "@rospogrigio"
], ],
"requirements": ["pycryptodome==3.9.8"], "requirements": ["cryptography==2.9.2"],
"config_flow": true "config_flow": true
} }

View File

@@ -45,14 +45,8 @@ import sys
import time import time
import binascii import binascii
try: from cryptography.hazmat.backends import default_backend
# raise ImportError from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import Crypto
from Crypto.Cipher import AES # PyCrypto
except ImportError:
Crypto = AES = None
import pyaes # https://github.com/ricmoo/pyaes
version_tuple = (8, 1, 0) version_tuple = (8, 1, 0)
version = version_string = __version__ = "%d.%d.%d" % version_tuple version = version_string = __version__ = "%d.%d.%d" % version_tuple
@@ -62,15 +56,6 @@ log = logging.getLogger(__name__)
logging.basicConfig() # TODO include function name/line numbers in log logging.basicConfig() # TODO include function name/line numbers in log
# log.setLevel(level=logging.DEBUG) # Uncomment to Debug # log.setLevel(level=logging.DEBUG) # Uncomment to Debug
log.debug("%s version %s", __name__, version)
log.debug("Python %s on %s", sys.version, sys.platform)
if Crypto is None:
log.debug("Using pyaes version %r", pyaes.VERSION)
log.debug("Using pyaes from %r", pyaes.__file__)
else:
log.debug("Using PyCrypto %r", Crypto.version_info)
log.debug("Using PyCrypto from %r", Crypto.__file__)
SET = "set" SET = "set"
STATUS = "status" STATUS = "status"
@@ -86,22 +71,13 @@ class AESCipher:
def __init__(self, key): def __init__(self, key):
"""Initialize a new AESCipher.""" """Initialize a new AESCipher."""
self.bs = 16 self.bs = 16
self.key = key self.cipher = Cipher(algorithms.AES(key), modes.ECB(), default_backend())
def encrypt(self, raw, use_base64=True): def encrypt(self, raw, use_base64=True):
"""Encrypt data to be sent to device.""" """Encrypt data to be sent to device."""
if Crypto: encryptor = self.cipher.encryptor()
raw = self._pad(raw) crypted_text = encryptor.update(self._pad(raw)) + encryptor.finalize()
cipher = AES.new(self.key, mode=AES.MODE_ECB)
crypted_text = cipher.encrypt(raw)
else:
_ = self._pad(raw)
cipher = pyaes.blockfeeder.Encrypter(
pyaes.AESModeOfOperationECB(self.key)
) # no IV, auto pads to 16
crypted_text = cipher.feed(raw)
crypted_text += cipher.feed() # flush final block
# print('crypted_text (%d) %r' % (len(crypted_text), crypted_text))
if use_base64: if use_base64:
return base64.b64encode(crypted_text) return base64.b64encode(crypted_text)
else: else:
@@ -111,23 +87,9 @@ class AESCipher:
"""Decrypt data from device.""" """Decrypt data from device."""
if use_base64: if use_base64:
enc = base64.b64decode(enc) enc = base64.b64decode(enc)
# print('enc (%d) %r' % (len(enc), enc))
# enc = self._unpad(enc) decryptor = self.cipher.decryptor()
# enc = self._pad(enc) return self._unpad(decryptor.update(enc) + decryptor.finalize()).decode()
# print('upadenc (%d) %r' % (len(enc), enc))
if Crypto:
cipher = AES.new(self.key, AES.MODE_ECB)
raw = cipher.decrypt(enc)
# print('raw (%d) %r' % (len(raw), raw))
return self._unpad(raw).decode("utf-8")
# return self._unpad(cipher.decrypt(enc)).decode('utf-8')
else:
cipher = pyaes.blockfeeder.Decrypter(
pyaes.AESModeOfOperationECB(self.key)
) # no IV, auto pads to 16
plain_text = cipher.feed(enc)
plain_text += cipher.feed() # flush final block
return plain_text
def _pad(self, s): def _pad(self, s):
padnum = self.bs - len(s) % self.bs padnum = self.bs - len(s) % self.bs

View File

@@ -2,4 +2,5 @@ black==20.8b1
codespell==1.17.1 codespell==1.17.1
flake8==3.8.3 flake8==3.8.3
mypy==0.782 mypy==0.782
pydocstyle==5.1.1 pydocstyle==5.1.1
cryptography==2.9.2