2023-07-01 23:03:50 +00:00
|
|
|
"""Original implementation of the TP-Link Smart Home protocol."""
|
2024-04-16 18:21:20 +00:00
|
|
|
|
2023-07-01 23:03:50 +00:00
|
|
|
import struct
|
2024-11-18 18:46:36 +00:00
|
|
|
from collections.abc import Generator
|
2023-07-01 23:03:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
class OriginalTPLinkSmartHomeProtocol:
|
|
|
|
"""Original implementation of the TP-Link Smart Home protocol."""
|
|
|
|
|
|
|
|
INITIALIZATION_VECTOR = 171
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _xor_payload(unencrypted: bytes) -> Generator[int, None, None]:
|
|
|
|
key = OriginalTPLinkSmartHomeProtocol.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.
|
|
|
|
|
|
|
|
:param request: plaintext request data
|
|
|
|
:return: ciphertext to be send over wire, in bytes
|
|
|
|
"""
|
|
|
|
plainbytes = request.encode()
|
|
|
|
return struct.pack(">I", len(plainbytes)) + bytes(
|
|
|
|
OriginalTPLinkSmartHomeProtocol._xor_payload(plainbytes)
|
|
|
|
)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _xor_encrypted_payload(ciphertext: bytes) -> Generator[int, None, None]:
|
|
|
|
key = OriginalTPLinkSmartHomeProtocol.INITIALIZATION_VECTOR
|
|
|
|
for cipherbyte in ciphertext:
|
|
|
|
plainbyte = key ^ cipherbyte
|
|
|
|
key = cipherbyte
|
|
|
|
yield plainbyte
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def decrypt(ciphertext: bytes) -> str:
|
|
|
|
"""Decrypt a response of a TP-Link Smart Home Device.
|
|
|
|
|
|
|
|
:param ciphertext: encrypted response data
|
|
|
|
:return: plaintext response
|
|
|
|
"""
|
|
|
|
return bytes(
|
|
|
|
OriginalTPLinkSmartHomeProtocol._xor_encrypted_payload(ciphertext)
|
|
|
|
).decode()
|