Switch to cryptograhy for crypto routines
This commit is contained in:
committed by
rospogrigio
parent
2879761eae
commit
b7173f3033
@@ -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):
|
||||||
|
@@ -6,6 +6,6 @@
|
|||||||
"codeowners": [
|
"codeowners": [
|
||||||
"@rospogrigio"
|
"@rospogrigio"
|
||||||
],
|
],
|
||||||
"requirements": ["pycryptodome==3.9.8"],
|
"requirements": ["cryptography==2.9.2"],
|
||||||
"config_flow": true
|
"config_flow": true
|
||||||
}
|
}
|
@@ -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
|
||||||
|
@@ -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
|
Reference in New Issue
Block a user