From c79ff46a815e24d324e698b96a9415ee63b35122 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 22 Sep 2021 06:17:45 -0500 Subject: [PATCH 1/5] Avoid temp array during encrypt --- kasa/protocol.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index 6ee6f72d6..2256fda5d 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -89,6 +89,13 @@ async def query(host: str, request: Union[str, Dict], retry_count: int = 3) -> D # make mypy happy, this should never be reached.. raise SmartDeviceException("Query reached somehow to unreachable") + @staticmethod + def _generate_tplink(unencrypted): + key = TPLinkSmartHomeProtocol.INITIALIZATION_VECTOR + for unencryptedbyte in unencrypted: + key = key ^ unencryptedbyte + yield key + @staticmethod def encrypt(request: str) -> bytes: """Encrypt a request for a TP-Link Smart Home Device. @@ -96,17 +103,10 @@ def encrypt(request: str) -> bytes: :param request: plaintext request data :return: ciphertext to be send over wire, in bytes """ - key = TPLinkSmartHomeProtocol.INITIALIZATION_VECTOR - plainbytes = request.encode() - buffer = bytearray(struct.pack(">I", len(plainbytes))) - - for plainbyte in plainbytes: - cipherbyte = key ^ plainbyte - key = cipherbyte - buffer.append(cipherbyte) - - return bytes(buffer) + return struct.pack(">I", len(plainbytes)) + bytes( + TPLinkSmartHomeProtocol._generate_tplink(plainbytes) + ) @staticmethod def decrypt(ciphertext: bytes) -> str: @@ -125,4 +125,4 @@ def decrypt(ciphertext: bytes) -> str: plaintext = bytes(buffer) - return plaintext.decode() + return plaintext.decode() \ No newline at end of file From 255d9528f540a25fa43f63d51926f498b4bec48e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 22 Sep 2021 06:22:05 -0500 Subject: [PATCH 2/5] black --- kasa/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index 2256fda5d..c504730e0 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -125,4 +125,4 @@ def decrypt(ciphertext: bytes) -> str: plaintext = bytes(buffer) - return plaintext.decode() \ No newline at end of file + return plaintext.decode() From 14513a111c7069d24b8e300af1148292b75c6295 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 23 Sep 2021 10:57:18 -0500 Subject: [PATCH 3/5] Update kasa/protocol.py Co-authored-by: Teemu R. --- kasa/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index c504730e0..5d6f720e9 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -90,7 +90,7 @@ async def query(host: str, request: Union[str, Dict], retry_count: int = 3) -> D raise SmartDeviceException("Query reached somehow to unreachable") @staticmethod - def _generate_tplink(unencrypted): + def _xor_payload(unencrypted): key = TPLinkSmartHomeProtocol.INITIALIZATION_VECTOR for unencryptedbyte in unencrypted: key = key ^ unencryptedbyte From f6fa8de339688a8e69cf9eb126c6357c70d6bbae Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 23 Sep 2021 10:57:58 -0500 Subject: [PATCH 4/5] Update kasa/protocol.py --- kasa/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index 5d6f720e9..dc599f413 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -105,7 +105,7 @@ def encrypt(request: str) -> bytes: """ plainbytes = request.encode() return struct.pack(">I", len(plainbytes)) + bytes( - TPLinkSmartHomeProtocol._generate_tplink(plainbytes) + TPLinkSmartHomeProtocol._xor_payload(plainbytes) ) @staticmethod From e78aa2fccdda2fe914f6bc9133c88c4155550c03 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 23 Sep 2021 11:02:13 -0500 Subject: [PATCH 5/5] update decrypt as well --- kasa/protocol.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/kasa/protocol.py b/kasa/protocol.py index dc599f413..bbf13b995 100755 --- a/kasa/protocol.py +++ b/kasa/protocol.py @@ -109,20 +109,20 @@ def encrypt(request: str) -> bytes: ) @staticmethod - def decrypt(ciphertext: bytes) -> str: - """Decrypt a response of a TP-Link Smart Home Device. - - :param ciphertext: encrypted response data - :return: plaintext response - """ + def _xor_encrypted_payload(ciphertext): key = TPLinkSmartHomeProtocol.INITIALIZATION_VECTOR - buffer = [] - for cipherbyte in ciphertext: plainbyte = key ^ cipherbyte key = cipherbyte - buffer.append(plainbyte) + yield plainbyte - plaintext = bytes(buffer) + @staticmethod + def decrypt(ciphertext: bytes) -> str: + """Decrypt a response of a TP-Link Smart Home Device. - return plaintext.decode() + :param ciphertext: encrypted response data + :return: plaintext response + """ + return bytes( + TPLinkSmartHomeProtocol._xor_encrypted_payload(ciphertext) + ).decode()