ccc_kdf.c
UWB key schedule + SP0 Pre-POLL frame codec.
Overview
UWB key schedule + SP0 Pre-POLL frame codec.
depends on ccc_kdf.h
API
Fstatic void put_be32(uint8_t *out, uint32_t v)
Store v big-endian into out (4 bytes).
out- Destination buffer for the 4 big-endian bytes.
v- Value to store.
ccc_derive_sts_v, ccc_derive_uad, kdf108_block, sp0_nonceFstatic uint32_t get_be32(const uint8_t *in)
Load a big-endian uint32 from in (4 bytes).
in- Source buffer holding 4 big-endian bytes.
- returns
- The decoded uint32 value.
ccc_derive_sts_vFstatic void xor_bytes(uint8_t *out, const uint8_t *a, const uint8_t *b, size_t n)
XOR n bytes: out = a ^ b (out may alias a).
out- Destination buffer for the XOR result.
a- First input buffer.
b- Second input buffer.
n- Number of bytes to XOR.
ccc_aes_cmac, ccc_sp0_decrypt, ccc_sp0_encrypt, sp0_cbc_mac, sp0_ctrFstatic uint8_t block_lshift1(const uint8_t in[AES_BLOCK_LEN], uint8_t out[AES_BLOCK_LEN])
One-bit left shift of a 128-bit big-endian block.
in- Input 128-bit block.
out- Output buffer receiving the shifted block.
- returns
- The bit shifted out of the most significant bit position.
cmac_subkeyFstatic void cmac_subkey(const uint8_t l[AES_BLOCK_LEN], uint8_t out[AES_BLOCK_LEN])
CMAC subkey derivation: K = (L << 1), XOR Rb if the top bit was set.
l- Input 128-bit value (L, or a previously derived subkey).
out- Output buffer receiving the derived subkey.
ccc_aes_cmac · calls block_lshift1Fint ccc_aes_cmac(const uint8_t *key, size_t key_bits, const uint8_t *msg, size_t msg_len, uint8_t tag[CCC_CMAC_TAG_LEN])
AES-CMAC authentication tag over message.
ccc_derive_salted_hash, kdf108_block · calls cmac_subkey, xor_bytesFstatic int kdf108_block(const uint8_t *kdk, size_t kdk_bits, uint32_t counter, const uint8_t *label, size_t label_len, const uint8_t *context, size_t ctx_len, uint32_t l_bits, uint8_t out[AES_BLOCK_LEN])
One counter-mode CMAC block: CMAC(kdk, counter || label || 0x00 || context || l_bits).
kdk- Key-derivation key.
kdk_bits- kdk size in bits.
counter- Block counter value.
label- KDF label bytes.
label_len- Length of label in bytes.
context- KDF context bytes (may be omitted if ctx_len is 0).
ctx_len- Length of context in bytes.
l_bits- Requested output length in bits, encoded into the KDF input.
out- Output buffer receiving the CMAC block.
- returns
- 0 on success; -E2BIG if the assembled KDF input exceeds the internal buffer; propagated CMAC error otherwise.
ccc_derive_mupsk1, ccc_derive_mupsk2, ccc_derive_mursk, ccc_derive_salted_hash, ccc_derive_uad, ccc_derive_ursk_kt, derive_dkey · calls ccc_aes_cmac, put_be32Fint ccc_derive_mupsk1(const uint8_t ursk[CCC_URSK_LEN], uint8_t out[CCC_MUPSK1_LEN])
Derive mUPSK1, the SP0 Pre-POLL AES-CCM* key.
kdf108_blockFint ccc_derive_mupsk2(const uint8_t ursk[CCC_URSK_LEN], uint8_t out[CCC_MUPSK2_LEN])
Derive mUPSK2, the seed for the UWB-address KDF.
kdf108_blockFint ccc_derive_mursk(const uint8_t ursk[CCC_URSK_LEN], uint8_t out[CCC_MURSK_LEN])
Derive mURSK, the ranging-key seed feeding URSK_KT.
kdf108_blockFint ccc_derive_salted_hash(const uint8_t ursk[CCC_URSK_LEN], const uint8_t *ranging_config, size_t rc_len, uint8_t out[CCC_SALTED_HASH_LEN])
Derive SaltedHash from the serialized ranging configuration.
ccc_aes_cmac, kdf108_blockFint ccc_derive_ursk_kt(const uint8_t mursk[CCC_MURSK_LEN], uint32_t sts_index, uint8_t out[CCC_URSK_KT_LEN])
Derive URSK_KT, generated once per ranging cycle and keyed by the STS index.
kdf108_blockFstatic int derive_dkey(const uint8_t ursk_kt[CCC_URSK_KT_LEN], const uint8_t label[4], const uint8_t salted_hash[CCC_SALTED_HASH_LEN], uint8_t out[CCC_DURSK_LEN])
Shared dURSK/dUDSK derivation body: CMAC(URSK_KT, ctr1 || label || 0x00 || SaltedHash || 0x000000 || 0x80).
ursk_kt- URSK_KT input key for the current ranging cycle.
label- 4-byte KDF label distinguishing dURSK from dUDSK.
salted_hash- SaltedHash of the ranging configuration.
out- Output buffer receiving the derived key.
- returns
- Result of the underlying KDF block derivation.
ccc_derive_dudsk, ccc_derive_dursk · calls kdf108_blockFint ccc_derive_dursk(const uint8_t ursk_kt[CCC_URSK_KT_LEN], const uint8_t salted_hash[CCC_SALTED_HASH_LEN], uint8_t out[CCC_DURSK_LEN])
Derive dURSK, per-cycle STS key material.
derive_dkeyFint ccc_derive_dudsk(const uint8_t ursk_kt[CCC_URSK_KT_LEN], const uint8_t salted_hash[CCC_SALTED_HASH_LEN], uint8_t out[CCC_DUDSK_LEN])
Derive dUDSK, per-cycle SP0 timestamp-frame key.
derive_dkeyFint ccc_derive_sts_v(const uint8_t salted_hash[CCC_SALTED_HASH_LEN], uint32_t sts_index, uint8_t out[CCC_STS_V_LEN])
Derive STS-V (phyHrpUwbStsV), the per-PPDU STS IV for the DW3000.
get_be32, put_be32Fint ccc_derive_uad(const uint8_t mupsk2[CCC_MUPSK2_LEN], uint32_t sts_index0, uint8_t out[CCC_UAD_LEN])
Derive UAD, the raw UWB-address derivation output.
kdf108_block, put_be32Fstatic void remap_if_reserved(uint8_t *addr, size_t len)
If addr is a reserved all-ones value (0xFFFF/0xFFFE for 2 bytes, 0xFF..FF for other lengths), clear its top bit.
addr- Address buffer checked and modified in place.
len- Length of addr in bytes.
ccc_uad_addressesFint ccc_uad_addresses(const uint8_t uad[CCC_UAD_LEN], uint8_t keysource[CCC_KEYSOURCE_LEN], uint8_t dest_short_addr[CCC_DEST_SHORT_ADDR_LEN], uint8_t src_long_addr[CCC_SRC_LONG_ADDR_LEN])
Split UAD into the UWB addresses (KeySource, destination short address, source long address).
remap_if_reservedFstatic void sp0_nonce(uint8_t nonce[CCC_SP0_NONCE_LEN], const uint8_t src_long_addr[CCC_SRC_LONG_ADDR_LEN], uint32_t frame_counter)
Build the SP0 CCM* nonce: SrcLongAddr || FrameCounter(BE) || SecLevel.
nonce- Output buffer receiving the assembled nonce.
src_long_addr- Source long address included in the nonce.
frame_counter- Frame counter encoded big-endian into the nonce.
ccc_sp0_decrypt, ccc_sp0_encrypt · calls put_be32Fstatic int sp0_cbc_mac(const uint8_t key[CCC_MUPSK1_LEN], const uint8_t nonce[CCC_SP0_NONCE_LEN], const uint8_t *mhr, size_t mhr_len, const uint8_t *payload, size_t payload_len, uint8_t tag[AES_BLOCK_LEN])
Compute the CCM* CBC-MAC over B0 || l(a)||MHR || payload, zero-padded per block.
key- AES-128 key used for the CBC-MAC.
nonce- SP0 CCM* nonce for this frame.
mhr- MAC header bytes forming the additional authenticated data (may be omitted if mhr_len is 0).
mhr_len- Length of mhr in bytes.
payload- Payload bytes to authenticate.
payload_len- Length of payload in bytes.
tag- Output buffer receiving the computed CBC-MAC tag.
- returns
- 0 on success; propagated error from AES encryption otherwise.
ccc_sp0_decrypt, ccc_sp0_encrypt · calls xor_bytesFstatic int sp0_ctr(const uint8_t key[CCC_MUPSK1_LEN], const uint8_t nonce[CCC_SP0_NONCE_LEN], const uint8_t *in, size_t len, uint8_t *out, uint8_t s0[AES_BLOCK_LEN])
Apply CCM* CTR mode: emit the S0 keystream block, then XOR keystream S1.. over in to out (symmetric encrypt/decrypt).
key- AES-128 key used for the CTR keystream.
nonce- SP0 CCM* nonce for this frame.
in- Input bytes to transform.
len- Length of in/out in bytes.
out- Output buffer receiving the transformed bytes.
s0- Output buffer receiving the S0 keystream block (used for MIC encryption).
- returns
- 0 on success; propagated error from AES encryption otherwise.
ccc_sp0_decrypt, ccc_sp0_encrypt · calls xor_bytesFstatic int sp0_ct_diff(const uint8_t *a, const uint8_t *b, size_t n)
Constant-time inequality: 0 iff the @p n bytes are equal.
ccc_sp0_decryptFint ccc_sp0_encrypt(const uint8_t key[CCC_MUPSK1_LEN], const uint8_t src_long_addr[CCC_SRC_LONG_ADDR_LEN], uint32_t frame_counter, const uint8_t *mhr, size_t mhr_len, const uint8_t *payload, size_t payload_len, uint8_t *ciphertext_out, uint8_t mic_out[CCC_SP0_MIC_LEN])
Encrypt + authenticate an SP0 data frame (AES-CCM*, ENC-MIC-64).
sp0_cbc_mac, sp0_ctr, sp0_nonce, xor_bytesFint ccc_sp0_decrypt(const uint8_t key[CCC_MUPSK1_LEN], const uint8_t src_long_addr[CCC_SRC_LONG_ADDR_LEN], uint32_t frame_counter, const uint8_t *mhr, size_t mhr_len, const uint8_t *ciphertext, size_t ciphertext_len, const uint8_t mic[CCC_SP0_MIC_LEN], uint8_t *payload_out)
Decrypt + verify an SP0 data frame; zeroes plaintext and returns -EBADMSG on MIC failure.
sp0_cbc_mac, sp0_ct_diff, sp0_ctr, sp0_nonce, xor_bytes