198 lines
4.9 KiB
C
198 lines
4.9 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <logging/log.h>
|
|
LOG_MODULE_REGISTER(net_ieee802154_security,
|
|
CONFIG_NET_L2_IEEE802154_LOG_LEVEL);
|
|
|
|
#include <crypto/cipher.h>
|
|
#include <net/net_core.h>
|
|
|
|
#include "ieee802154_frame.h"
|
|
#include "ieee802154_security.h"
|
|
|
|
extern const uint8_t level_2_tag_size[4];
|
|
|
|
int ieee802154_security_setup_session(struct ieee802154_security_ctx *sec_ctx,
|
|
uint8_t level, uint8_t key_mode,
|
|
uint8_t *key, uint8_t key_len)
|
|
{
|
|
uint8_t tag_size;
|
|
int ret;
|
|
|
|
if (level > IEEE802154_SECURITY_LEVEL_ENC_MIC_128 ||
|
|
key_mode > IEEE802154_KEY_ID_MODE_SRC_8_INDEX) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* ToDo: supporting other key modes */
|
|
if (level > IEEE802154_SECURITY_LEVEL_NONE &&
|
|
(key_len > IEEE802154_KEY_MAX_LEN || !key ||
|
|
key_mode != IEEE802154_KEY_ID_MODE_IMPLICIT)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (level >= IEEE802154_SECURITY_LEVEL_ENC) {
|
|
tag_size = level_2_tag_size[level - 4];
|
|
} else {
|
|
tag_size = level_2_tag_size[level];
|
|
}
|
|
|
|
sec_ctx->level = level;
|
|
|
|
if (level > IEEE802154_SECURITY_LEVEL_NONE) {
|
|
memcpy(sec_ctx->key, key, key_len);
|
|
sec_ctx->key_len = key_len;
|
|
sec_ctx->key_mode = key_mode;
|
|
|
|
sec_ctx->enc.key.bit_stream = sec_ctx->key;
|
|
sec_ctx->enc.keylen = sec_ctx->key_len;
|
|
|
|
sec_ctx->dec.key.bit_stream = sec_ctx->key;
|
|
sec_ctx->dec.keylen = sec_ctx->key_len;
|
|
}
|
|
|
|
sec_ctx->enc.mode_params.ccm_info.tag_len = tag_size;
|
|
sec_ctx->dec.mode_params.ccm_info.tag_len = tag_size;
|
|
|
|
ret = cipher_begin_session(sec_ctx->enc.device, &sec_ctx->enc,
|
|
CRYPTO_CIPHER_ALGO_AES,
|
|
CRYPTO_CIPHER_MODE_CCM,
|
|
CRYPTO_CIPHER_OP_ENCRYPT);
|
|
if (ret) {
|
|
NET_ERR("Could not setup encryption context");
|
|
|
|
return ret;
|
|
}
|
|
|
|
ret = cipher_begin_session(sec_ctx->dec.device, &sec_ctx->dec,
|
|
CRYPTO_CIPHER_ALGO_AES,
|
|
CRYPTO_CIPHER_MODE_CCM,
|
|
CRYPTO_CIPHER_OP_DECRYPT);
|
|
if (ret) {
|
|
NET_ERR("Could not setup decryption context");
|
|
cipher_free_session(sec_ctx->enc.device, &sec_ctx->enc);
|
|
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool ieee802154_decrypt_auth(struct ieee802154_security_ctx *sec_ctx,
|
|
uint8_t *frame,
|
|
uint8_t auth_payload_len,
|
|
uint8_t decrypt_payload_len,
|
|
uint8_t *src_ext_addr,
|
|
uint32_t frame_counter)
|
|
{
|
|
struct cipher_aead_pkt apkt;
|
|
struct cipher_pkt pkt;
|
|
uint8_t nonce[13];
|
|
int ret;
|
|
|
|
if (!sec_ctx || sec_ctx->level == IEEE802154_SECURITY_LEVEL_NONE) {
|
|
return true;
|
|
}
|
|
|
|
/* See Section 7.3.2 */
|
|
memcpy(nonce, src_ext_addr, IEEE802154_EXT_ADDR_LENGTH);
|
|
nonce[8] = (uint8_t)(frame_counter >> 24);
|
|
nonce[9] = (uint8_t)(frame_counter >> 16);
|
|
nonce[10] = (uint8_t)(frame_counter >> 8);
|
|
nonce[11] = (uint8_t)frame_counter;
|
|
nonce[12] = sec_ctx->level;
|
|
|
|
pkt.in_buf = decrypt_payload_len ? frame + auth_payload_len : NULL;
|
|
pkt.in_len = decrypt_payload_len;
|
|
pkt.out_buf = frame;
|
|
pkt.out_buf_max = IEEE802154_MTU - IEEE802154_MFR_LENGTH;
|
|
|
|
apkt.ad = frame;
|
|
apkt.ad_len = auth_payload_len;
|
|
apkt.tag = sec_ctx->dec.mode_params.ccm_info.tag_len ?
|
|
frame + auth_payload_len + decrypt_payload_len : NULL;
|
|
apkt.pkt = &pkt;
|
|
|
|
ret = cipher_ccm_op(&sec_ctx->dec, &apkt, nonce);
|
|
if (ret) {
|
|
NET_ERR("Cannot decrypt/auth (%i): %p %u/%u - fc %u",
|
|
ret, frame, auth_payload_len, decrypt_payload_len,
|
|
frame_counter);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ieee802154_encrypt_auth(struct ieee802154_security_ctx *sec_ctx,
|
|
uint8_t *frame,
|
|
uint8_t auth_payload_len,
|
|
uint8_t encrypt_payload_len,
|
|
uint8_t *src_ext_addr)
|
|
{
|
|
struct cipher_aead_pkt apkt;
|
|
struct cipher_pkt pkt;
|
|
uint8_t nonce[13];
|
|
int ret;
|
|
|
|
if (!sec_ctx || sec_ctx->level == IEEE802154_SECURITY_LEVEL_NONE) {
|
|
return true;
|
|
}
|
|
|
|
/* See Section 7.3.2 */
|
|
memcpy(nonce, src_ext_addr, IEEE802154_EXT_ADDR_LENGTH);
|
|
sys_put_be32(sec_ctx->frame_counter, &nonce[8]);
|
|
nonce[12] = sec_ctx->level;
|
|
|
|
pkt.in_buf = encrypt_payload_len ? frame + auth_payload_len : NULL;
|
|
pkt.in_len = encrypt_payload_len;
|
|
pkt.out_buf = frame;
|
|
pkt.out_buf_max = IEEE802154_MTU - IEEE802154_MFR_LENGTH;
|
|
|
|
apkt.ad = frame;
|
|
apkt.ad_len = auth_payload_len;
|
|
apkt.tag = NULL;
|
|
apkt.pkt = &pkt;
|
|
|
|
ret = cipher_ccm_op(&sec_ctx->enc, &apkt, nonce);
|
|
if (ret) {
|
|
NET_ERR("Cannot encrypt/auth (%i): %p %u/%u - fc %u",
|
|
ret, frame, auth_payload_len, encrypt_payload_len,
|
|
sec_ctx->frame_counter);
|
|
return false;
|
|
}
|
|
|
|
sec_ctx->frame_counter++;
|
|
|
|
return true;
|
|
}
|
|
|
|
int ieee802154_security_init(struct ieee802154_security_ctx *sec_ctx)
|
|
{
|
|
const struct device *dev;
|
|
|
|
(void)memset(&sec_ctx->enc, 0, sizeof(struct cipher_ctx));
|
|
(void)memset(&sec_ctx->dec, 0, sizeof(struct cipher_ctx));
|
|
|
|
dev = device_get_binding(
|
|
CONFIG_NET_L2_IEEE802154_SECURITY_CRYPTO_DEV_NAME);
|
|
if (!dev) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
sec_ctx->enc.flags = cipher_query_hwcaps(dev);
|
|
sec_ctx->dec.flags = cipher_query_hwcaps(dev);
|
|
|
|
sec_ctx->enc.mode_params.ccm_info.nonce_len = 13U;
|
|
sec_ctx->dec.mode_params.ccm_info.nonce_len = 13U;
|
|
|
|
sec_ctx->enc.device = dev;
|
|
sec_ctx->dec.device = dev;
|
|
|
|
return 0;
|
|
}
|