Kbox-UniStack Docs

KNX Data Secure

Enable KNX Data Secure on the kbox-stack — MakeSecure setup, static SIO sizing and buffers, wiring into MakeStack, FDSK factory reset, and certification.

The stack ships KNX Data Secure in the same .a — no compile-time switch. You enable it by constructing a secure object with MakeSecure() and passing the resulting ISecurity& into the Secure overload of MakeStack().

Overview

The device is a System B end device: Device Descriptor Type 0 0x07B0, S-Mode configuration, default manufacturer id 0x023E. Data Secure adds AES-128 CCM wrap/unwrap, sequence-number anti-replay, and a Security Interface Object (SIO). The classic (plain) and secure paths coexist; the constructor you call decides which is active.

The secure counter store and the SIO key tables are persisted through a single KnxFlashLayout& (built once, up front, by MakeFlashLayout() from one base flash region — see Stack Construction · MakeFlashLayout). MakeSecure() reads its counter/key regions from layout.CounterView()/ layout.SioKeyView(). Concrete flash addresses are platform-specific — see the STM32 (HAL) platform pages.

MakeSecure signature

MakeSecure() placement-news the secure object into an opaque SecureStackStorage you own and returns an ISecurity&. The C4 / DC-2 invariants (separate AES contexts; a single shared monotonic counter store) are established inside MakeSecure() — you do not wire them by hand.

ISecurity& MakeSecure(SecureStackStorage& storage,
                      KnxFlashLayout&  layout,
                      const SioSizing& sizing,
                      const SioBuffers& buffers,
                      KnxAddress       deviceIA,
                      IClock&          clock);

Prefer the bundle form when wiring a new device — it derives sizing/buffers from your SioSizing and makes deviceIA an optional trailing argument (default KnxAddress(0xFFFFu), the S-Mode "unprogrammed" address):

ISecurity& MakeSecure(KnxSecureDeviceStorage<S>& device, KnxFlashLayout& layout,
                      IClock& clock, KnxAddress deviceIA = KnxAddress(0xFFFFu));

See API Reference · Consumer storage bundles.

As with the stack, SecureStackStorage and every reference passed to MakeSecure() must have static / file-scope lifetime — the returned ISecurity& points into that storage. See Integration Contract.

Sizing & buffers

Secure storage is statically sized. You declare how many keys/roles the device supports with SioSizing, size the persistence buffers with the SIO_COMMIT_BUF_SIZE(...) macro, and hand pointers to those buffers in SioBuffers.

struct SioSizing {
  uint16_t grpKeyCount;
  uint16_t p2pKeyCount;
  uint16_t iaCount;
  uint16_t goFlagCount;
  uint16_t roleCount;
};

// Commit-image size derived from the same counts.
#define SIO_COMMIT_BUF_SIZE(grp, p2p, ia, go, role)                \
  (2u + 16u + (grp) * 18u + (p2p) * 20u + (ia) * 8u + (go) * 1u +  \
   (role) * 4u + 6u + 1u + 1u + 6u + 8u + 10u + 1u)

SioBuffers holds the raw pointers the secure object writes through — the tool key, group / P2P / IA / GO-flag / role tables, the sequence-number and mode bytes, the report control and report buffers, and the commit image (with its commitImageCap).

All secure buffers are static — no allocation happens at run time. The sizing counts must match the buffer capacities you provision (use SIO_COMMIT_BUF_SIZE(...) for the commit image). Undersizing a table silently corrupts secure state, so size deliberately.

Wiring into MakeStack

Build the flash layout first, then call MakeSecure(), then pass the returned ISecurity& as the final argument of the Secure MakeStack overload. The bundle form (KnxSecureDeviceStorage<S>, from Builder/KnxDeviceStorage.h) is the recommended way to hold all of this device's storage — it replaces the older pattern of four separate storage variables plus a hand-threaded sioBuffers global.

static KnxDeviceStorage device;
KnxFlashLayout& layout = MakeFlashLayout(
    device, baseFlash, stackParameters, /*userDataPageCount=*/1u);

IKnxStack& stack = MakeStack(
    device, stackParameters, busDriver, watchDog, knxLed,
    clock, transmitter, button, layout);
static constexpr SioSizing kSioSizing = {5u, 0u, 16u, 8u, 0u};
static KnxSecureDeviceStorage<kSioSizing> device;

KnxFlashLayout& layout = MakeFlashLayout(
    device, baseFlash, stackParameters, /*userDataPageCount=*/1u);

ISecurity& secure = MakeSecure(device, layout, clock);  // deviceIA default 0xFFFF

IKnxStack& stack = MakeStack(
    device, stackParameters, busDriver, watchDog, knxLed,
    clock, transmitter, button, layout,
    secure);          // ← ISecurity& enables Data Secure

For the full construction flow (both modes) see Stack Construction.

FDSK & factory reset

The Factory Default Setup Key is a 16-byte value carried in StackParameters::fdsk[16]. It seeds the tool key so a commissioning tool can first reach the device securely. Set it through StackParameters::SetFdsk(...) — not by assigning the fdsk member directly — once, before stack.Init():

// 16-byte FDSK — printed on the device label, entered into ETS.
static constexpr uint8_t kDeviceFdsk[16] = { /* ... */ };

// Call once, before stack.Init(); the stack applies it during Init()
// (first-boot Tool Key bootstrap + runtime factory-reset).
stackParameters.SetFdsk(kDeviceFdsk);

ISecurity exposes the factory-reset hooks the stack drives: a reset that restores the tool key from the FDSK, and one that clears secure state without changing the individual address. The device serial is set through SetDeviceSerial(...).

The FDSK is a secret. In production it is unique per device and printed on the device label; do not ship a fixed or all-zero FDSK.

Certification

KNX Data Secure is part of the device's certification scope (System B, mask 0x07B0, S-Mode). See Certification for the PICS / PIXIT declaration and the Application Notes covered.