mirror of
https://github.com/python-kasa/python-kasa.git
synced 2026-11-06 11:57:26 +00:00
Split KLAP IoT updates into smaller requests and validate KLAP responses (#1829)
Some checks failed
CI / Perform Lint Checks (3.15) (push) Has been cancelled
CodeQL Checks / Analyze (python) (push) Has been cancelled
CI / Python 3.11 on macos-latest (push) Has been cancelled
CI / Python 3.12 on macos-latest (push) Has been cancelled
CI / Python 3.13 on macos-latest (push) Has been cancelled
CI / Python 3.14 on macos-latest (push) Has been cancelled
CI / Python 3.15 on macos-latest (push) Has been cancelled
CI / Python 3.11 on ubuntu-latest (push) Has been cancelled
CI / Python 3.12 on ubuntu-latest (push) Has been cancelled
CI / Python 3.13 on ubuntu-latest (push) Has been cancelled
CI / Python 3.14 on ubuntu-latest (push) Has been cancelled
CI / Python 3.15 on ubuntu-latest (push) Has been cancelled
CI / Python 3.11 on windows-latest (push) Has been cancelled
CI / Python 3.12 on windows-latest (push) Has been cancelled
CI / Python 3.13 on windows-latest (push) Has been cancelled
CI / Python 3.14 on windows-latest (push) Has been cancelled
CI / Python 3.15 on windows-latest (push) Has been cancelled
Some checks failed
CI / Perform Lint Checks (3.15) (push) Has been cancelled
CodeQL Checks / Analyze (python) (push) Has been cancelled
CI / Python 3.11 on macos-latest (push) Has been cancelled
CI / Python 3.12 on macos-latest (push) Has been cancelled
CI / Python 3.13 on macos-latest (push) Has been cancelled
CI / Python 3.14 on macos-latest (push) Has been cancelled
CI / Python 3.15 on macos-latest (push) Has been cancelled
CI / Python 3.11 on ubuntu-latest (push) Has been cancelled
CI / Python 3.12 on ubuntu-latest (push) Has been cancelled
CI / Python 3.13 on ubuntu-latest (push) Has been cancelled
CI / Python 3.14 on ubuntu-latest (push) Has been cancelled
CI / Python 3.15 on ubuntu-latest (push) Has been cancelled
CI / Python 3.11 on windows-latest (push) Has been cancelled
CI / Python 3.12 on windows-latest (push) Has been cancelled
CI / Python 3.13 on windows-latest (push) Has been cancelled
CI / Python 3.14 on windows-latest (push) Has been cancelled
CI / Python 3.15 on windows-latest (push) Has been cancelled
Some IoT devices respond over KLAP with a plain `200 OK` html page instead of a proper response when the response would be too large to construct, causing a "not a multiple of the block length" decryption error (e.g., KS200M in #1828). This PR lowers the maximum response size to 2048 bytes for IoT devices using KLAP, so that the update is split into multiple smaller requests like it is already done for bulbs. In details: - `IotDevice.max_device_response_size` returns 2048 over KLAP. Bulbs keep 4096 and XOR devices keep 16 KiB. - `KlapTransport` checks the response length and signature before decrypting, and raises a `KasaException` telling what was wrong instead of the decryption error. Fixes #1828 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@ import asyncio
|
||||
import base64
|
||||
import datetime
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
import secrets
|
||||
import struct
|
||||
@@ -396,6 +397,18 @@ class KlapTransport(BaseTransport):
|
||||
if TYPE_CHECKING:
|
||||
assert self._encryption_session
|
||||
assert isinstance(response_data, bytes)
|
||||
# A message is a 32 byte signature followed by whole AES blocks.
|
||||
# Some devices answer with a plain html page instead.
|
||||
if len(response_data) < 48 or (len(response_data) - 32) % 16:
|
||||
raise KasaException(
|
||||
f"Device {self._host} sent a response that is not a KLAP "
|
||||
f"message ({len(response_data)} bytes): {response_data[:64]!r}"
|
||||
)
|
||||
if not self._encryption_session.is_signed(response_data, seq):
|
||||
raise KasaException(
|
||||
f"Device {self._host} sent a response with an invalid "
|
||||
f"signature for request with seq {seq}"
|
||||
)
|
||||
try:
|
||||
decrypted_response = self._encryption_session.decrypt(response_data)
|
||||
except Exception as ex:
|
||||
@@ -535,6 +548,11 @@ class KlapEncryptionSession:
|
||||
).digest()
|
||||
return (signature + ciphertext, self._seq)
|
||||
|
||||
def is_signed(self, msg: bytes, seq: int) -> bool:
|
||||
"""Return whether the message is signed for the request with seq."""
|
||||
signature = _sha256(self._sig + PACK_SIGNED_LONG(seq) + msg[32:])
|
||||
return hmac.compare_digest(msg[:32], signature)
|
||||
|
||||
def decrypt(self, msg: bytes) -> str:
|
||||
"""Decrypt the data."""
|
||||
decryptor = self._cipher.decryptor()
|
||||
|
||||
Reference in New Issue
Block a user