Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
esphome::home_io_control::crypto Namespace Reference

Functions

void compute_checksum (uint8_t byte, uint8_t &c1, uint8_t &c2)
 Proprietary checksum algorithm used in IV construction.
void construct_iv (const uint8_t *data, uint8_t len, const uint8_t challenge[HMAC_SIZE], uint8_t iv[IV_SIZE])
 Construct the 16-byte initialization vector (IV) for AES encryption.
bool aes128_encrypt (const uint8_t in[AES_BLOCK_SIZE], const uint8_t key[AES_KEY_SIZE], uint8_t out[AES_BLOCK_SIZE])
 AES-128 ECB encrypt a single 16-byte block.
bool aes128_decrypt (const uint8_t in[AES_BLOCK_SIZE], const uint8_t key[AES_KEY_SIZE], uint8_t out[AES_BLOCK_SIZE])
 AES‑128 ECB decrypt a single 16‑byte block.
bool create_hmac (const uint8_t *data, uint8_t len, const uint8_t challenge[HMAC_SIZE], const uint8_t key[AES_KEY_SIZE], uint8_t hmac[HMAC_SIZE])
 Create a 6-byte HMAC for authentication (proprietary IO-Homecontrol scheme).
bool verify_hmac (const uint8_t *data, uint8_t len, const uint8_t hmac[HMAC_SIZE], const uint8_t challenge[HMAC_SIZE], const uint8_t key[AES_KEY_SIZE])
 Verify a received HMAC using constant-time comparison.
bool crypt_key (const uint8_t *data, uint8_t len, const uint8_t challenge[HMAC_SIZE], const uint8_t in[AES_KEY_SIZE], uint8_t out[AES_KEY_SIZE])
 Encrypt or decrypt a system key during pairing.
void generate_challenge (uint8_t out[HMAC_SIZE])
 Generate 6 random bytes for a challenge using the ESP32 hardware RNG.

Function Documentation

◆ aes128_decrypt()

bool esphome::home_io_control::crypto::aes128_decrypt ( const uint8_t in[AES_BLOCK_SIZE],
const uint8_t key[AES_KEY_SIZE],
uint8_t out[AES_BLOCK_SIZE] )

AES‑128 ECB decrypt a single 16‑byte block.

Parameters
in16‑byte ciphertext block.
key16‑byte AES key.
outOutput: 16‑byte plaintext block.
Returns
true on success.

Definition at line 311 of file proto_crypto.cpp.

◆ aes128_encrypt()

bool esphome::home_io_control::crypto::aes128_encrypt ( const uint8_t in[AES_BLOCK_SIZE],
const uint8_t key[AES_KEY_SIZE],
uint8_t out[AES_BLOCK_SIZE] )

AES-128 ECB encrypt a single 16-byte block.

AES‑128 ECB encrypt a single 16‑byte block.

Parameters
in16‑byte plaintext block.
key16‑byte AES key.
outOutput: 16‑byte ciphertext block.
Returns
true on success.

Definition at line 307 of file proto_crypto.cpp.

◆ compute_checksum()

void esphome::home_io_control::crypto::compute_checksum ( uint8_t byte,
uint8_t & c1,
uint8_t & c2 )

Proprietary checksum algorithm used in IV construction.

Update running checksum bytes (c1, c2) with a new data byte (IO‑Homecontrol IV derivation).

This is NOT a standard CRC - it's a custom accumulator used by the IO-Homecontrol protocol to mix frame data into the initialization vector for AES encryption.

Parameters
byteInput data byte.
c1First checksum byte (inout).
c2Second checksum byte (inout).

Definition at line 269 of file proto_crypto.cpp.

◆ construct_iv()

void esphome::home_io_control::crypto::construct_iv ( const uint8_t * data,
uint8_t len,
const uint8_t challenge[HMAC_SIZE],
uint8_t iv[IV_SIZE] )

Construct the 16-byte initialization vector (IV) for AES encryption.

Construct the 16‑byte IV for AES encryption from frame data and challenge.

Layout: [bytes 0-7: frame data or 0x55 padding] [bytes 8-9: checksums] [bytes 10-15: challenge] The IV binds the HMAC to both the frame content and the random challenge, preventing replay attacks.

Layout: bytes 0–7 = up to 8 frame bytes padded with 0x55, bytes 8–9 = checksums, bytes 10–15 = challenge.

Parameters
dataFrame data bytes.
lenNumber of data bytes.
challenge6‑byte challenge from the device.
ivOutput: 16‑byte IV.

Definition at line 289 of file proto_crypto.cpp.

Here is the call graph for this function:

◆ create_hmac()

bool esphome::home_io_control::crypto::create_hmac ( const uint8_t * data,
uint8_t len,
const uint8_t challenge[HMAC_SIZE],
const uint8_t key[AES_KEY_SIZE],
uint8_t hmac[HMAC_SIZE] )

Create a 6-byte HMAC for authentication (proprietary IO-Homecontrol scheme).

Create a 6‑byte HMAC for authentication (IO‑Homecontrol proprietary scheme).

See proto_crypto.h for full parameter documentation and construction details.

Process: build IV from [data + challenge] → AES‑128‑ECB encrypt IV with system key → take first 6 bytes. This is NOT a standard HMAC; it is specific to IO‑Homecontrol and matches the protocol specification as implemented in compatible devices.

Parameters
dataFrame data bytes (usually command + payload).
lenLength of data.
challenge6‑byte random challenge.
key16‑byte system key.
hmacOutput: 6‑byte HMAC.
Note
The IV construction appends two checksum bytes derived from the data stream (see compute_checksum()) followed by the 6‑byte challenge, padded to 16 bytes with 0x55. The AES result is truncated to 6 bytes for transmission.
Returns
true on success.

Definition at line 317 of file proto_crypto.cpp.

Here is the call graph for this function:

◆ crypt_key()

bool esphome::home_io_control::crypto::crypt_key ( const uint8_t * data,
uint8_t len,
const uint8_t challenge[HMAC_SIZE],
const uint8_t in[AES_KEY_SIZE],
uint8_t out[AES_KEY_SIZE] )

Encrypt or decrypt a system key during pairing.

Encrypt or decrypt the system key during pairing (XOR with AES‑encrypted IV).

The system key is XORed with AES(IV, TRANSFER_KEY) - the same operation encrypts and decrypts. The TRANSFER_KEY is a hardcoded key known to all IO-Homecontrol devices.

The same operation works for both directions: encrypting for the device and decrypting the device's acknowledgement.

Parameters
dataFrame data (typically the key‑init command byte).
lenLength of data (usually 1).
challengeDevice's 6‑byte challenge.
inInput key (plaintext for encrypt, ciphertext for decrypt).
outOutput key.
Warning
This primitive is used ONLY during the key‑transfer phase (0x32). The resulting system key is then used for all normal authenticated exchanges. Never call this with arbitrary data outside the pairing sequence.
Returns
true on success.

Definition at line 347 of file proto_crypto.cpp.

Here is the call graph for this function:

◆ generate_challenge()

void esphome::home_io_control::crypto::generate_challenge ( uint8_t out[HMAC_SIZE])

Generate 6 random bytes for a challenge using the ESP32 hardware RNG.

Generate 6 random bytes for a challenge using the ESP hardware RNG.

Parameters
outOutput buffer (6 bytes).

Definition at line 360 of file proto_crypto.cpp.

◆ verify_hmac()

bool esphome::home_io_control::crypto::verify_hmac ( const uint8_t * data,
uint8_t len,
const uint8_t hmac[HMAC_SIZE],
const uint8_t challenge[HMAC_SIZE],
const uint8_t key[AES_KEY_SIZE] )

Verify a received HMAC using constant-time comparison.

Verify a received 6‑byte HMAC using constant‑time comparison.

Full documentation in proto_crypto.h.

Parameters
dataFrame data bytes.
lenLength of data.
hmacReceived 6‑byte HMAC.
challengeChallenge used in HMAC calculation.
key16‑byte system key.
Returns
true if HMAC matches.

Definition at line 331 of file proto_crypto.cpp.

Here is the call graph for this function: