Szyfrowanie i skróty
Funkcje skryptu TapHome dla szyfrowanych i podpisanych protokołów urządzeń: AESENCRYPT i AESDECRYPT, HASH i HMAC z MD5 i SHA, RANDBYTES oraz przykład bramy Bosch KM200.
Funkcje szyfrowania i skrótów budują to, czego oczekuje urządzenie z szyfrowanym lub podpisanym interfejsem lokalnym: szyfrowanie AES, skróty MD5 i SHA, podpisy HMAC i bezpieczne losowe bajty. Tylko budują wartości, więc działają w każdym skrypcie. Wszystkie wymagają Core 2026.1 w TapHome Next, kompilacja 40991 lub nowsza (jeszcze nie w oficjalnym wydaniu). Base64, tekst szesnastkowy i sumy kontrolne CRC są na stronie Kodowanie bajtów i sumy kontrolne.
Przyjmują dane bajtowe: collection<uint8>, blob lub tekst. Tekst jest używany jako bajty ISO-8859-1. W przeciwieństwie do funkcji TOBYTES bez kodowania, która zamienia inne znaki na ?, znak spoza ISO-8859-1 jest tu błędem — dla UTF-8 przekaż TOBYTES(text, "utf-8"). Wynikiem jest collection<uint8>.
HASH, HMAC
HASH oblicza skrót danych bajtowych, HMAC ich skrót z kluczem (podpis).
| |
| Nazwa | Opis |
|---|---|
data | Dane bajtowe, z których liczy się skrót. |
key | Klucz HMAC, dane bajtowe. |
algorithm | "MD5", "SHA1", "SHA256" lub "SHA512", bez rozróżniania wielkości liter; akceptowane są też "SHA-1", "SHA-256" i "SHA-512". |
Zwraca — collection<uint8> o długości 16, 20, 32 lub 64 bajtów.
Uwagi — HMAC przyjmuje klucz jako pierwszy, w tej samej kolejności co hmac.new(key, msg, digest) w Pythonie.
Przykład
TOHEX(HASH("abc", "MD5"));
# Result: "900150983cd24fb0d6963f7d28e17f72"
TOHEX(HMAC("Jefe", "what do ya want for nothing?", "SHA256"));
# Result: "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"Błędy — HASH Unknown algorithm. Valid values are ‘MD5’, ‘SHA1’, ‘SHA256’, ‘SHA512’; HASH - data contains characters outside ISO-8859-1, convert the text with TOBYTES(text, “utf-8”); HASH - data must be a uint8 collection, a blob or a string. Komunikaty HMAC zaczynają się od jego własnej nazwy i podają argument.
Dostępność — Core 2026.1 w TapHome Next, kompilacja 40991 lub nowsza (jeszcze nie w oficjalnym wydaniu).
AESENCRYPT, AESDECRYPT
AESENCRYPT szyfruje dane bajtowe algorytmem AES, AESDECRYPT je odszyfrowuje.
| |
| Nazwa | Opis |
|---|---|
data | Dane bajtowe. Dane dla AESDECRYPT muszą mieć długość będącą wielokrotnością 16 bajtów. |
key | 16, 24 lub 32 bajty: AES-128, AES-192 lub AES-256. |
mode | "ECB" lub "CBC", opcjonalnie z dopełnieniem, na przykład "CBC/PKCS7" lub "ECB/ZEROS"; bez rozróżniania wielkości liter. |
iv | 16 bajtów, wymagany przez CBC. ECB go nie przyjmuje — pomiń argument lub przekaż Null. |
| Dopełnienie (padding) | AESENCRYPT | AESDECRYPT |
|---|---|---|
/PKCS7 (domyślne; /PKCS5, nazwa z Javy, oznacza to samo) | Dodaje dopełnienie. | Usuwa je. |
/ZEROS | Wypełnia ostatni blok bajtami 0x00; dane, które już kończą się na granicy bloku, nie dostają nic, puste dane pozostają puste. | Usuwa wszystkie końcowe bajty 0x00, także te, które należą do danych — używaj go do tekstu, takiego jak JSON. |
/NONE | Bez dopełnienia; długość danych musi być wielokrotnością 16 bajtów. | Nic nie usuwa. |
Zwraca — collection<uint8>.
Uwagi — Błędny klucz może zauważyć tylko /PKCS7, i to nie zawsze; przy /ZEROS i /NONE błędny klucz zwraca błędne bajty bez błędu. Błędny iv w CBC psuje tylko pierwsze 16 bajtów i nigdy nie jest zgłaszany.
Przykład
VAR key := BYTECOLLECTION("2b7e151628aed2a6abf7158809cf4f3c");
VAR iv := BYTECOLLECTION("000102030405060708090a0b0c0d0e0f");
VAR secret := AESENCRYPT("Hello World", key, "CBC", iv);
TOSTRING(AESDECRYPT(secret, key, "CBC", iv));
# Result: "Hello World"Błędy — AESDECRYPT - decryption failed, check the key, the iv and the padding (dopełnienie /PKCS7 się nie zgadza: błędny klucz lub dane niezaszyfrowane z PKCS7); AESENCRYPT - key must be 16, 24 or 32 bytes long (AES-128, AES-192, AES-256), it is N; AESENCRYPT - CBC mode needs a 16-byte iv, it is N; AESENCRYPT - ECB mode does not use an iv, leave the argument out; AESENCRYPT Unknown mode. Valid values are ‘ECB’, ‘CBC’, optionally followed by ‘/PKCS7’ (or ‘/PKCS5’), ‘/ZEROS’ or ‘/NONE’; AESENCRYPT - with padding NONE the data length must be a multiple of 16 bytes, it is N; AESDECRYPT - encrypted data length must be a multiple of 16 bytes, it is N. Każda funkcja podaje w komunikacie swoją nazwę.
Dostępność — Core 2026.1 w TapHome Next, kompilacja 40991 lub nowsza (jeszcze nie w oficjalnym wydaniu).
RANDBYTES
RANDBYTES zwraca kryptograficznie bezpieczne losowe bajty — dla iv trybu CBC, nonce lub klucza sesji.
| |
Zwraca — collection<uint8> o długości count bajtów, od 1 do 2048; to samo co secrets.token_bytes(n) lub os.urandom(n) w Pythonie.
Uwagi
- RAND i RANDINT nie są bezpieczne i nie wolno ich używać do klucza,
ivani nonce. - Zmienna z kolekcją przypisana do innej zmiennej to ta sama kolekcja, więc przed
APPENDzróbCOPY— inaczej urośnie teżiv.
Przykład — nowy iv przed zaszyfrowanymi danymi, tak jak wysyła go wiele protokołów
VAR key := FROMHEX("2b7e151628aed2a6abf7158809cf4f3c");
VAR iv := RANDBYTES(16);
VAR body := COPY(iv);
APPEND(body, AESENCRYPT("Hello World", key, "CBC", iv));
TOSTRING(AESDECRYPT(COPY(body, 16), key, "CBC", COPY(body, 0, 16)));
# Result: "Hello World"Błędy — RANDBYTES: count must be between 1 and 2048.
Dostępność — Core 2026.1 w TapHome Next, kompilacja 40991 lub nowsza (jeszcze nie w oficjalnym wydaniu).
Przykład — brama Bosch / Buderus KM200
Interfejs HTTP bramy Bosch / Buderus KM200, używanej też przez IVT Rego 2000, tak jak opisują go projekty społeczności (producent go nie publikuje). Treść odpowiedzi to Base64 danych AES-256-ECB dopełnionych zerami, a klucz składa się z dwóch skrótów MD5:
VAR salt := BYTECOLLECTION("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"); # 32-byte vendor salt
VAR k1 := TOBYTES(REPLACE("xxxx-xxxx-xxxx-xxxx", "-", "")); # gateway password
APPEND(k1, salt);
VAR k2 := COPY(salt);
APPEND(k2, TOBYTES("my private password"));
VAR key := HASH(k1, "MD5");
APPEND(key, HASH(k2, "MD5")); # 32 bytes = AES-256
VAR r := SENDHTTPREQUEST("/system/healthStatus", "GET", "", "User-Agent: TeleHeater/2.2.3");
# value = a module variable that keeps the result
IF r.IsSuccess
value := PARSEJSON(TOSTRING(AESDECRYPT(FROMBASE64(r.Content), key, "ECB/ZEROS"), "utf-8"), "value");
ELSE
ADDERROR(r.StatusCode + " (" + r.ReasonPhrase + ")");
ENDZobacz też — Funkcje Packet parser, Kodowanie bajtów i sumy kontrolne, Tekst i kolekcje.