View Source Grizzly.ZWave.CommandClasses.S0 (grizzly v8.5.1)

S0 (Security) Command Class

Summary

Functions

Derive the S0 authentication key (for calculating MACs) from the network key.

Derive the S0 encryption key (for calculating MACs) from the network key.

Functions

Link to this function

authentication_key(network_key)

View Source
@spec authentication_key(<<_::128>>) :: <<_::128>>

Derive the S0 authentication key (for calculating MACs) from the network key.

This is done by encrypting the S0 authentication vector (0x55 repeated 16 times) with the network key using AES-128-ECB.

Link to this function

calculate_mac(network_key, command_byte, sender_node_id, receiver_node_id, sender_nonce, receiver_nonce, encrypted_payload)

View Source
@spec calculate_mac(
  network_key :: <<_::128>>,
  command_byte :: 129 | 193,
  sender_node_id :: pos_integer(),
  receiver_node_id :: pos_integer(),
  sender_nonce :: <<_::64>>,
  receiver_nonce :: <<_::64>>,
  encrypted_payload :: binary()
) :: <<_::64>>

Calculates the MAC for an S0 Message Encapsulation command.

First, a block of authorization data is created by concatenating the following values: the IV, the command byte (0x81 or 0xC1), the sender node ID, the receiver node ID, the length of the encrypted payload, and the encrypted payload itself.

The IV is constructed by concatenating the sender nonce (which is included in the command -- in the spec, this is the "initialization vector" field) with the receiver nonce (which was obtained via a Nonce Get/Report exchange).

Because this is unclear in the docs, it is important to note that the sequencing byte (which includes the second frame, sequenced, and sequence counter fields) is part of the encrypted payload, which is why it isn't included in the auth data block.

The auth data block is then padded to the block size (16 bytes for AES-128) and then encrypted in 16-byte blocks using the network authentication key (see authentication_key/1). The IV used for the first block is 16 bytes of 0x00, and the IV for each subsequent block is the output from the previous block.

The MAC is the first 8 bytes of the final block.

Link to this function

decrypt(network_key, sender_nonce, receiver_nonce, payload)

View Source
Link to this function

encrypt(network_key, sender_nonce, receiver_nonce, payload)

View Source
Link to this function

encryption_key(network_key)

View Source
@spec encryption_key(<<_::128>>) :: <<_::128>>

Derive the S0 encryption key (for calculating MACs) from the network key.

This is done by encrypting the S0 encryption vector (0xAA repeated 16 times) with the network key using AES-128-ECB.