mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
444 lines
16 KiB
C
444 lines
16 KiB
C
/*
|
|
* Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @defgroup net_ieee802154_security IEEE 802.15.4 security
|
|
* @ingroup net_ieee802154
|
|
* @brief IEEE 802.15.4 security header
|
|
*
|
|
* @warning
|
|
* This module is exposing raw 802.15.4 encryption without an underlying key
|
|
* management framework. This is intended for experimentation with the security
|
|
* modes of 802.15.4, and not for use cases where its security is depended on.
|
|
*
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief IEEE 802.15.4 security interface
|
|
*
|
|
* Specification: IEEE 802.15.4 - 2015
|
|
* https://www.silabs.com/content/usergenerated/asi/cloud/attachments/siliconlabs/en/community/wireless/proprietary/forum/jcr:content/content/primary/qna/802_15_4_promiscuous-tbzR/hivukadin_vukadi-iTXQ/802.15.4-2015.pdf
|
|
*
|
|
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
|
|
*/
|
|
|
|
#ifndef NET_IEEE802154_SECURITY_H
|
|
#define NET_IEEE802154_SECURITY_H
|
|
|
|
#include <stdint.h>
|
|
#include "ieee802154.h"
|
|
#include "crypto/ciphers.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Forward declaration of an IEEE 802.15.4 abstract security device
|
|
*/
|
|
typedef struct ieee802154_sec_dev ieee802154_sec_dev_t;
|
|
|
|
/**
|
|
* @brief Struct of security operations
|
|
*
|
|
* @note A device can indicate that the fallback implementations should be
|
|
* used by setting the corresponding member to `NULL`, or pointing to
|
|
* @ref ieee802154_radio_cipher_ops, which does the same. Note that
|
|
* @ref ieee802154_radio_cipher_ops is the default security operations
|
|
* driver assigned when @ref ieee802154_sec_init is called.
|
|
*/
|
|
typedef struct ieee802154_radio_cipher_ops {
|
|
/**
|
|
* @brief Function to set the encryption key for the
|
|
* next cipher operation
|
|
*
|
|
* @param[in] dev Will be @ref ieee802154_sec_context_t::ieee802154_sec_dev_t
|
|
* @param[in] key Key to be used for the next cipher operation
|
|
* @param[in] key_size key size in bytes
|
|
*/
|
|
void (*set_key)(ieee802154_sec_dev_t *dev,
|
|
const uint8_t *key,
|
|
uint8_t key_size);
|
|
/**
|
|
* @brief Function type to compute CBC-MAC
|
|
*
|
|
* @param[in] dev Will be @ref ieee802154_sec_context_t::ieee802154_sec_dev_t
|
|
* @param[in] cipher Output cipher blocks
|
|
* @param[in, out] iv in: IV; out: computed MIC
|
|
* @param[in] plain Input plain blocks
|
|
* @param[in] nblocks Number of blocks
|
|
*/
|
|
void (*cbc)(const ieee802154_sec_dev_t *dev,
|
|
uint8_t *cipher,
|
|
uint8_t *iv,
|
|
const uint8_t *plain,
|
|
uint8_t nblocks);
|
|
/**
|
|
* @brief Function type to perform ECB encryption
|
|
*
|
|
* @param[in] dev Will be @ref ieee802154_sec_context_t::ieee802154_sec_dev_t
|
|
* @param[out] cipher Output cipher blocks
|
|
* @param[in] plain Input plain blocks
|
|
* @param[in] nblocks Number of blocks
|
|
*/
|
|
void (*ecb)(const ieee802154_sec_dev_t *dev,
|
|
uint8_t *cipher,
|
|
const uint8_t *plain,
|
|
uint8_t nblocks);
|
|
} ieee802154_radio_cipher_ops_t;
|
|
|
|
/**
|
|
* @brief IEEE 802.15.4 security device descriptor
|
|
*/
|
|
struct ieee802154_sec_dev {
|
|
/**
|
|
* @brief Pointer to the operations of the device
|
|
*/
|
|
const struct ieee802154_radio_cipher_ops *cipher_ops;
|
|
/**
|
|
* @brief Pointer to the context of the device
|
|
*/
|
|
void *ctx;
|
|
};
|
|
|
|
#if !defined(CONFIG_IEEE802154_SEC_DEFAULT_KEY) || defined(DOXYGEN)
|
|
/**
|
|
* @brief AES default key
|
|
*
|
|
* @note Predefine it yourself,
|
|
* if you want another key to be set up on initialization
|
|
*/
|
|
#define CONFIG_IEEE802154_SEC_DEFAULT_KEY "pizza_margherita"
|
|
#endif
|
|
|
|
/**
|
|
* @brief Length of an AES key in bytes
|
|
*/
|
|
#define IEEE802154_SEC_KEY_LENGTH (16U)
|
|
|
|
/**
|
|
* @brief Block size of an encryption block
|
|
*/
|
|
#define IEEE802154_SEC_BLOCK_SIZE (16U)
|
|
|
|
/**
|
|
* @brief Maximum length of the security auxiliary header in bytes
|
|
*/
|
|
#define IEEE802154_SEC_MAX_AUX_HDR_LEN (14U)
|
|
|
|
/**
|
|
* @brief Maximum Size of IEEE 802.15.4 MAC
|
|
*/
|
|
#define IEEE802154_SEC_MAX_MAC_SIZE (16U)
|
|
|
|
/**
|
|
* @brief Mask to get security level bits
|
|
*/
|
|
#define IEEE802154_SEC_SCF_SECLEVEL_MASK (0x07)
|
|
|
|
/**
|
|
* @brief Number of shifts to set/get security level bits
|
|
*/
|
|
#define IEEE802154_SEC_SCF_SECLEVEL_SHIFT (0)
|
|
|
|
/**
|
|
* @brief Mask to get key mode bits
|
|
*/
|
|
#define IEEE802154_SEC_SCF_KEYMODE_MASK (0x18)
|
|
|
|
/**
|
|
* @brief Number of shifts to set/get key mode bits
|
|
*/
|
|
#define IEEE802154_SEC_SCF_KEYMODE_SHIFT (3)
|
|
|
|
/**
|
|
* @brief Security levels
|
|
*
|
|
* <em>IEEE802154_SEC_SCF_SECLEVEL_MIC*</em>:
|
|
* A message integrity code (MIC), also known as MAC,
|
|
* is used to prove authentication. The MIC covers the whole frame
|
|
* i.e. header, auxiliary header, and frame payload.
|
|
* The MIC is always encrypted, thus it must be decrypted by the receiver,
|
|
* to be checked.
|
|
*
|
|
* <em>IEEE802154_SEC_SCF_SECLEVEL_ENC*</em>:
|
|
* AES-128 in ECB mode is used to encrypt the payload of a frame to provide
|
|
* confidentiality.
|
|
*
|
|
* <em>IEEE802154_SEC_SCF_SECLEVEL_ENC_MIC*</em>:
|
|
* A combination of the two modes above is used to ensure
|
|
* authentication and confidentiality.
|
|
*/
|
|
typedef enum {
|
|
IEEE802154_SEC_SCF_SECLEVEL_NONE = 0x00, /**< no security */
|
|
IEEE802154_SEC_SCF_SECLEVEL_MIC32 = 0x01, /**< 32 bit MIC */
|
|
IEEE802154_SEC_SCF_SECLEVEL_MIC64 = 0x02, /**< 64 bit MIC */
|
|
IEEE802154_SEC_SCF_SECLEVEL_MIC128 = 0x03, /**< 128 bit MIC */
|
|
IEEE802154_SEC_SCF_SECLEVEL_ENC = 0x04, /**< encryption */
|
|
IEEE802154_SEC_SCF_SECLEVEL_ENC_MIC32 = 0x05, /**< enc. + 32 bit MIC */
|
|
IEEE802154_SEC_SCF_SECLEVEL_ENC_MIC64 = 0x06, /**< enc. + 64 bit MIC (mandatory) */
|
|
IEEE802154_SEC_SCF_SECLEVEL_ENC_MIC128 = 0x07 /**< enc. + 128 bit MIC */
|
|
} ieee802154_sec_scf_seclevel_t;
|
|
|
|
/**
|
|
* @brief Key identifier modes
|
|
*
|
|
* The key identifier field in the auxiliary header
|
|
* consists of the key source and the key index fields and is only present
|
|
* if the key identifier mode is not IEEE802154_SEC_SCF_KEYMODE_IMPLICIT.
|
|
* (see 9.4.3 in the spec.)
|
|
*
|
|
* +----------------+-------------+------------------+------------------------------------+
|
|
* | mode | key source | key index | description |
|
|
* +----------------+-------------+------------------+------------------------------------+
|
|
* | IMPLICIT | 0 bytes | 0 bytes | The key is implicitly |
|
|
* | | | | known to the receiver. |
|
|
* +----------------+-------------+------------------+------------------------------------+
|
|
* | INDEX | 0 bytes | 1 byte | The key can be determined |
|
|
* | | | | from the key index. |
|
|
* +----------------+-------------+------------------+------------------------------------+
|
|
* | SHORT_INDEX | 4 bytes | 1 byte | The key is a group key and can be |
|
|
* | | | | determined from the key index and |
|
|
* | | | | the source PAN ID and the |
|
|
* | | | | short source address |
|
|
* | | | | of the originator of the frame. |
|
|
* +----------------+-------------+------------------+------------------------------------+
|
|
* | HW_INDEX | 8 bytes | 1 byte | The key can be determined |
|
|
* | | | | from the key index and |
|
|
* | | | | the long address of the originator |
|
|
* | | | | of the frame. |
|
|
* +----------------+-------------+------------------+------------------------------------+
|
|
*/
|
|
typedef enum {
|
|
IEEE802154_SEC_SCF_KEYMODE_IMPLICIT = 0x00, /**< Key is determined implicitly */
|
|
IEEE802154_SEC_SCF_KEYMODE_INDEX = 0x01, /**< Key is determined from key index */
|
|
IEEE802154_SEC_SCF_KEYMODE_SHORT_INDEX = 0x02, /**< Key is determined from 4 byte key source and key index */
|
|
IEEE802154_SEC_SCF_KEYMODE_HW_INDEX = 0x03 /**< Key is determined from 8 byte key source and key index */
|
|
} ieee802154_sec_scf_keymode_t;
|
|
|
|
/**
|
|
* @brief IEEE 802.15.4 security error codes
|
|
*/
|
|
typedef enum {
|
|
IEEE802154_SEC_OK, /**< Everything went fine */
|
|
IEEE802154_SEC_FRAME_COUNTER_OVERFLOW, /**< The requested operation would let the frame counter overflow */
|
|
IEEE802154_SEC_NO_KEY, /**< Could not find the key to perform a requested cipher operation */
|
|
IEEE802154_SEC_MAC_CHECK_FAILURE, /**< The computet MAC did not match */
|
|
IEEE802154_SEC_UNSUPORTED, /**< Unsupported operation */
|
|
} ieee802154_sec_error_t;
|
|
|
|
/**
|
|
* @brief Struct to hold IEEE 802.15.4 security information
|
|
*/
|
|
typedef struct ieee802154_sec_context {
|
|
/**
|
|
* @brief Cipher context with AES128 interface and key storage
|
|
*/
|
|
cipher_t cipher;
|
|
/**
|
|
* @brief Security level IEEE802154_SEC_SCF_SECLEVEL_*
|
|
*/
|
|
uint8_t security_level;
|
|
/**
|
|
* @brief Key mode IEEE802154_SEC_SCF_KEYMODE_*
|
|
*/
|
|
uint8_t key_id_mode;
|
|
/**
|
|
* @brief Key index
|
|
*/
|
|
uint8_t key_index;
|
|
/**
|
|
* @brief Key source
|
|
*
|
|
* Content depends on key_id_mode
|
|
*/
|
|
uint8_t key_source[IEEE802154_LONG_ADDRESS_LEN];
|
|
/**
|
|
* @brief Own frame counter
|
|
*/
|
|
uint32_t frame_counter;
|
|
/**
|
|
* @brief 802.15.4 security dev
|
|
*/
|
|
ieee802154_sec_dev_t dev;
|
|
} ieee802154_sec_context_t;
|
|
|
|
/**
|
|
* @brief IEEE 802.15.4 auxiliary security header
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
/**
|
|
* @brief Security Control field (SCF)
|
|
*
|
|
* Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
|
|
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
|
* | security level | key id. mode | fc sup.| ASN | r | r |
|
|
* +--------+--------+--------+--------+--------+--------+--------+--------+
|
|
*
|
|
* security level:
|
|
* one of IEEE802154_SEC_SCF_SECLEVEL_*
|
|
* key identifier mode:
|
|
* one of IEEE802154_SEC_SCF_KEY_*
|
|
* frame counter suppression:
|
|
* basically always zero because we do not support TSCH right now
|
|
* ASN:
|
|
* basically always zero because we do not support TSCG right now
|
|
*/
|
|
uint8_t scf;
|
|
/**
|
|
* @brief frame counter
|
|
*/
|
|
uint32_t fc;
|
|
/**
|
|
* @brief key identifier (0 - 9 bytes) according to key id. mode
|
|
*/
|
|
uint8_t key_id[];
|
|
} ieee802154_sec_aux_t;
|
|
|
|
/**
|
|
* @brief Content of key_source if key mode is IEEE802154_SEC_SCF_KEYMODE_INDEX
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
/**
|
|
* @brief Key index of key from originator, defined by key source
|
|
*/
|
|
uint8_t key_index;
|
|
} ieee802154_sec_aux_key_identifier_1_t;
|
|
|
|
/**
|
|
* @brief Content of key_source if key mode is IEEE802154_SEC_SCF_KEYMODE_SHORT_INDEX
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
/**
|
|
* @brief macPANId concatenated with macShortAddress
|
|
*/
|
|
uint8_t key_source[4];
|
|
/**
|
|
* @brief Key index of key from originator, defined by key source
|
|
*/
|
|
uint8_t key_index;
|
|
} ieee802154_sec_aux_key_identifier_5_t;
|
|
|
|
/**
|
|
* @brief Content of key_source if key mode is IEEE802154_SEC_SCF_KEYMODE_HW_INDEX
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
/**
|
|
* @brief macExtendedAddress
|
|
*/
|
|
uint8_t key_source[IEEE802154_LONG_ADDRESS_LEN];
|
|
/**
|
|
* @brief Key index of key from originator, defined by key source
|
|
*/
|
|
uint8_t key_index;
|
|
} ieee802154_sec_aux_key_identifier_9_t;
|
|
|
|
/**
|
|
* @brief Format of 13 byte nonce
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
/**
|
|
* @brief Source long address
|
|
*/
|
|
uint8_t src_addr[IEEE802154_LONG_ADDRESS_LEN];
|
|
/**
|
|
* @brief Frame counter
|
|
*/
|
|
uint32_t frame_counter;
|
|
/**
|
|
* @brief One of IEEE802154_SEC_SCF_SECLEVEL_*
|
|
*/
|
|
uint8_t security_level;
|
|
} ieee802154_sec_ccm_nonce_t;
|
|
|
|
/**
|
|
* @brief Format of 16 byte input block of CCM
|
|
*/
|
|
typedef struct __attribute__((packed)) {
|
|
/**
|
|
* @brief Flags field
|
|
*/
|
|
uint8_t flags;
|
|
/**
|
|
* @brief Nonce (Number that is only used once)
|
|
*/
|
|
ieee802154_sec_ccm_nonce_t nonce;
|
|
/**
|
|
* @brief Either the length of the actual message (for CBC-MAC) or
|
|
* a block counter (for CTR)
|
|
*/
|
|
uint16_t counter;
|
|
} ieee802154_sec_ccm_block_t;
|
|
|
|
/**
|
|
* @brief Initialize IEEE 802.15.4 security context with default values
|
|
*
|
|
* @param[out] ctx IEEE 802.15.4 security context
|
|
*/
|
|
void ieee802154_sec_init(ieee802154_sec_context_t *ctx);
|
|
|
|
/**
|
|
* @brief Encrypt IEEE 802.15.4 frame according to @p ctx
|
|
*
|
|
* @param[in] ctx IEEE 802.15.4 security context
|
|
* @param[in] header Pointer to frame header
|
|
* @param[in, out] header_size in: Header size; out: Size of header and auxiliary header
|
|
* @param[in,out] payload in: Plain payload; out: Encrypted payload
|
|
* @param[in] payload_size Size of payload
|
|
* @param[out] mic Buffer to store computed MIC
|
|
* @param[out] mic_size Size of MIC
|
|
* @param[in] src_address Source address
|
|
*
|
|
* @pre @p header should be large enough to also store the auxiliary header
|
|
*
|
|
* @return 0 Success
|
|
* @return negative integer on error
|
|
*/
|
|
int ieee802154_sec_encrypt_frame(ieee802154_sec_context_t *ctx,
|
|
const uint8_t *header, uint8_t *header_size,
|
|
uint8_t *payload, uint16_t payload_size,
|
|
uint8_t *mic, uint8_t *mic_size,
|
|
const uint8_t *src_address);
|
|
|
|
/**
|
|
* @brief Decrypt IEEE 802.15.4 frame according to @p ctx
|
|
*
|
|
* @param[in] ctx IEEE 802.15.4 security context
|
|
* @param[in] frame_size Size of received frame
|
|
* @param[in] header Pointer to header, which is also the frame
|
|
* @param[in, out] header_size in: Header size; out: Size of header and auxiliary header
|
|
* @param[out] payload Will point to the beginning of the payload
|
|
* @param[out] payload_size Pointer to store the payload size
|
|
* @param[out] mic Will point to the beginning of the MIC
|
|
* @param[out] mic_size Pointer to store the size of the MIC
|
|
* @param[in] src_address Pointer to remote long source address
|
|
*
|
|
* @pre After @p header follows the auxiliary header
|
|
*
|
|
* @return 0 Success
|
|
* @return negative integer on error
|
|
*/
|
|
int ieee802154_sec_decrypt_frame(ieee802154_sec_context_t *ctx,
|
|
uint16_t frame_size,
|
|
uint8_t *header, uint8_t *header_size,
|
|
uint8_t **payload, uint16_t *payload_size,
|
|
uint8_t **mic, uint8_t *mic_size,
|
|
const uint8_t *src_address);
|
|
|
|
/**
|
|
* @brief Default descriptor that will fallback to default implementations
|
|
*/
|
|
extern const ieee802154_radio_cipher_ops_t ieee802154_radio_cipher_ops;
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* NET_IEEE802154_SECURITY_H */
|
|
/** @} */
|