TapHome

Encryption and hashes

TapHome script functions for encrypted and signed device protocols: AESENCRYPT and AESDECRYPT, HASH and HMAC with MD5 and SHA, RANDBYTES, and a Bosch KM200 example.

Last updated:

The encryption and hash functions build what a device with an encrypted or signed local interface expects: AES encryption, MD5 and SHA hashes, HMAC signatures and secure random bytes. They only build values, so they work in every script. All of them need TapHome Next 2026.1.40991+. Base64, hexadecimal text and CRC checksums are in Byte encodings and checksums.

They take byte data: a collection<uint8>, a blob or a string. A string is used as ISO-8859-1 bytes. Unlike TOBYTES without an encoding, which turns other characters into ?, a character outside ISO-8859-1 is an error here — for UTF-8 pass TOBYTES(text, "utf-8"). The result is a collection<uint8>.

HASH, HMAC

HASH computes the hash of byte data, HMAC a keyed hash (a signature) of it.

1
2
HASH(data, algorithm)
HMAC(key, data, algorithm)
NameDescription
dataByte data to hash.
keyKey of HMAC, byte data.
algorithm"MD5", "SHA1", "SHA256" or "SHA512", not case sensitive; "SHA-1", "SHA-256" and "SHA-512" are accepted too.

Returns — collection<uint8> of 16, 20, 32 or 64 bytes.

Remarks — HMAC takes the key first, in the same order as Python’s hmac.new(key, msg, digest).

Example

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

Errors — 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. The messages of HMAC start with its own name and name the argument.

Available — TapHome Next 2026.1.40991+.

AESENCRYPT, AESDECRYPT

AESENCRYPT encrypts byte data with AES, AESDECRYPT decrypts it.

1
2
AESENCRYPT(data, key, mode [, iv])
AESDECRYPT(data, key, mode [, iv])
NameDescription
dataByte data. Data for AESDECRYPT must have a length that is a multiple of 16 bytes.
key16, 24 or 32 bytes: AES-128, AES-192 or AES-256.
mode"ECB" or "CBC", optionally followed by the padding, for example "CBC/PKCS7" or "ECB/ZEROS"; not case sensitive.
iv16 bytes, required by CBC. ECB takes none — leave the argument out or pass Null.
PaddingAESENCRYPTAESDECRYPT
/PKCS7 (default; /PKCS5, the Java name, means the same)Adds the padding.Removes it.
/ZEROSFills the last block with 0x00 bytes; data that already ends on a block boundary gets none, empty data stays empty.Removes all trailing 0x00 bytes, also those that belong to the data — use it for text such as JSON.
/NONENo padding; the data length must be a multiple of 16 bytes.Removes nothing.

Returns — collection<uint8>.

Remarks — Only /PKCS7 can notice a wrong key, and not always; with /ZEROS and /NONE a wrong key returns wrong bytes without an error. A wrong iv in CBC garbles only the first 16 bytes and is never reported.

Example

# key and iv as bytes
VAR key := BYTECOLLECTION("2b7e151628aed2a6abf7158809cf4f3c");
VAR iv := BYTECOLLECTION("000102030405060708090a0b0c0d0e0f");
# encrypt the text
VAR secret := AESENCRYPT("Hello World", key, "CBC", iv);
# decrypt and return the text
TOSTRING(AESDECRYPT(secret, key, "CBC", iv));
# Result: "Hello World"

Errors — AESDECRYPT - decryption failed, check the key, the iv and the padding (the /PKCS7 padding does not match: a wrong key, or data not encrypted with 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. Each function names itself in the message.

Available — TapHome Next 2026.1.40991+.

RANDBYTES

RANDBYTES returns cryptographically secure random bytes — for a CBC iv, a nonce or a session key.

1
RANDBYTES(count)

Returns — collection<uint8> of count bytes, 1 to 2048; the same as Python’s secrets.token_bytes(n) or os.urandom(n).

Remarks

  • RAND and RANDINT are not secure and must not be used for a key, an iv or a nonce.
  • A collection variable assigned to another variable is the same collection, so take a COPY before you APPEND to it — otherwise the iv grows too.

Example — a fresh iv in front of the encrypted data, as many protocols send it

# key and a fresh random iv
VAR key := FROMHEX("2b7e151628aed2a6abf7158809cf4f3c");
VAR iv := RANDBYTES(16);
# start the body with the iv
VAR body := COPY(iv);
# append the encrypted data
APPEND(body, AESENCRYPT("Hello World", key, "CBC", iv));
# split off the iv, decrypt, return the text
TOSTRING(AESDECRYPT(COPY(body, 16), key, "CBC", COPY(body, 0, 16)));
# Result: "Hello World"

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

Available — TapHome Next 2026.1.40991+.

Example — Bosch / Buderus KM200 gateway

The HTTP interface of a Bosch / Buderus KM200 gateway, also used by IVT Rego 2000, as community projects describe it (the manufacturer does not publish it). The body is Base64 of AES-256-ECB data padded with zeros, and the key is made of two MD5 hashes:

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

See also — Packet parser functions, Byte encodings and checksums, Text and collections.