---
title: "Encryption and hashes"
description: "TapHome script encryption: AES-128, AES-192 and AES-256 in ECB and CBC mode, padding, MD5 and SHA hashes, HMAC signatures and secure random bytes for an iv."
url: "https://taphome.com/en/docs/script/encryption-and-hashes/"
language: en
lastmod: 2026-11-06
generator: hugo
ai:
  topics: ["encryption","hashes","packet-parser","scripting-language"]
  questions: ["How do I encrypt or decrypt AES data in a TapHome script?","How do I sign a request with HMAC-SHA256 in a TapHome script?","How do I create a random iv in a TapHome script?","Which Core version do the encryption functions need?"]
---

# 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: 2026-11-06

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](https://taphome.com/en/docs/script/byte-encodings/).

They take **byte data**: a `collection<uint8>`, a blob or a string. A string is used as ISO-8859-1 bytes. Unlike [TOBYTES](https://taphome.com/en/docs/script/data-type-conversions/#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.

```text
HASH(data, algorithm)
HMAC(key, data, algorithm)
```

| Name | Description |
|---|---|
| `data` | Byte data to hash. |
| `key` | Key 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**

```taphome
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.

```text
AESENCRYPT(data, key, mode [, iv])
AESDECRYPT(data, key, mode [, iv])
```

| Name | Description |
|---|---|
| `data` | Byte data. Data for `AESDECRYPT` must have a length that is a multiple of 16 bytes. |
| `key` | 16, 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. |
| `iv` | 16 bytes, required by `CBC`. `ECB` takes none — leave the argument out or pass `Null`. |

| Padding | `AESENCRYPT` | `AESDECRYPT` |
|---|---|---|
| `/PKCS7` (default; `/PKCS5`, the Java name, means the same) | Adds the padding. | Removes it. |
| `/ZEROS` | Fills 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. |
| `/NONE` | No 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**

```taphome
# 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.

```text
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](https://taphome.com/en/docs/script/rounding-and-random/#rand) 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**

```taphome
# 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:

```taphome
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](https://taphome.com/en/docs/script/packet-parser/), [Byte encodings and checksums](https://taphome.com/en/docs/script/byte-encodings/), [Text and collections](https://taphome.com/en/docs/script/text-string-and-byte-array/).
