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));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 SecureFor 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.