TapHome

Crittografia e hash

Funzioni dello script TapHome per protocolli di dispositivi cifrati e firmati: AESENCRYPT e AESDECRYPT, HASH e HMAC con MD5 e SHA, RANDBYTES e un esempio per Bosch KM200.

Le funzioni di crittografia e hash costruiscono ciò che si aspetta un dispositivo con un’interfaccia locale cifrata o firmata: cifratura AES, hash MD5 e SHA, firme HMAC e byte casuali sicuri. Costruiscono solo valori, quindi funzionano in ogni script. Tutte richiedono Core 2026.1 su TapHome Next, build 40991 o più recente (non ancora nella versione ufficiale). Base64, testo esadecimale e checksum CRC si trovano in Codifiche di byte e checksum.

Accettano dati in byte: una collection<uint8>, un blob o una stringa. Una stringa viene usata come byte ISO-8859-1. A differenza di TOBYTES senza codifica, che trasforma gli altri caratteri in ?, qui un carattere fuori da ISO-8859-1 è un errore — per UTF-8 passa TOBYTES(text, "utf-8"). Il risultato è una collection<uint8>.

HASH, HMAC

HASH calcola l’hash di dati in byte, HMAC un loro hash con chiave (una firma).

1
2
HASH(data, algorithm)
HMAC(key, data, algorithm)
NomeDescrizione
dataDati in byte di cui calcolare l’hash.
keyChiave di HMAC, dati in byte.
algorithm"MD5", "SHA1", "SHA256" o "SHA512", senza distinzione tra maiuscole e minuscole; sono accettati anche "SHA-1", "SHA-256" e "SHA-512".

Valore restituito — collection<uint8> di 16, 20, 32 o 64 byte.

Note — HMAC prende per prima la chiave, nello stesso ordine di hmac.new(key, msg, digest) in Python.

Esempio

TOHEX(HASH("abc", "MD5"));
# Result: "900150983cd24fb0d6963f7d28e17f72"
TOHEX(HMAC("Jefe", "what do ya want for nothing?", "SHA256"));
# Result: "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"

Errori — 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. I messaggi di HMAC iniziano con il suo nome e indicano l’argomento.

Disponibile — Core 2026.1 su TapHome Next, build 40991 o più recente (non ancora nella versione ufficiale).

AESENCRYPT, AESDECRYPT

AESENCRYPT cifra dati in byte con AES, AESDECRYPT li decifra.

1
2
AESENCRYPT(data, key, mode [, iv])
AESDECRYPT(data, key, mode [, iv])
NomeDescrizione
dataDati in byte. I dati per AESDECRYPT devono avere una lunghezza multipla di 16 byte.
key16, 24 o 32 byte: AES-128, AES-192 o AES-256.
mode"ECB" o "CBC", seguito facoltativamente dal padding, per esempio "CBC/PKCS7" o "ECB/ZEROS"; senza distinzione tra maiuscole e minuscole.
iv16 byte, richiesto da CBC. ECB non lo usa — ometti l’argomento o passa Null.
PaddingAESENCRYPTAESDECRYPT
/PKCS7 (predefinito; /PKCS5, il nome Java, significa lo stesso)Aggiunge il padding.Lo rimuove.
/ZEROSRiempie l’ultimo blocco con byte 0x00; i dati che terminano già al confine di un blocco non ne ricevono, i dati vuoti restano vuoti.Rimuove tutti i byte 0x00 finali, anche quelli che appartengono ai dati — usalo per testo come JSON.
/NONENessun padding; la lunghezza dei dati deve essere un multiplo di 16 byte.Non rimuove nulla.

Valore restituito — collection<uint8>.

Note — Solo /PKCS7 può accorgersi di una chiave sbagliata, e non sempre; con /ZEROS e /NONE una chiave sbagliata restituisce byte sbagliati senza errore. Un iv sbagliato in CBC altera solo i primi 16 byte e non viene mai segnalato.

Esempio

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"

Errori — AESDECRYPT - decryption failed, check the key, the iv and the padding (il padding /PKCS7 non corrisponde: una chiave sbagliata o dati non cifrati con 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. Ogni funzione indica nel messaggio il proprio nome.

Disponibile — Core 2026.1 su TapHome Next, build 40991 o più recente (non ancora nella versione ufficiale).

RANDBYTES

RANDBYTES restituisce byte casuali crittograficamente sicuri — per un iv di CBC, un nonce o una chiave di sessione.

1
RANDBYTES(count)

Valore restituito — collection<uint8> di count byte, da 1 a 2048; lo stesso di secrets.token_bytes(n) o os.urandom(n) in Python.

Note

  • RAND e RANDINT non sono sicure e non vanno usate per una chiave, un iv o un nonce.
  • Una variabile collezione assegnata a un’altra variabile è la stessa collezione, quindi fai una COPY prima di aggiungere con APPEND — altrimenti cresce anche l’iv.

Esempio — un nuovo iv davanti ai dati cifrati, come lo inviano molti protocolli

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"

Errori — RANDBYTES: count must be between 1 and 2048.

Disponibile — Core 2026.1 su TapHome Next, build 40991 o più recente (non ancora nella versione ufficiale).

Esempio — gateway Bosch / Buderus KM200

L’interfaccia HTTP di un gateway Bosch / Buderus KM200, usato anche da IVT Rego 2000, come la descrivono i progetti della comunità (il produttore non la pubblica). Il corpo è Base64 di dati AES-256-ECB riempiti con zeri, e la chiave è composta da due hash 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 + ")");
END

Vedi anche — Funzioni Packet parser, Codifiche di byte e checksum, Testo e collezioni.