diff --git a/features/lorawan/LoRaWANInterface.cpp b/features/lorawan/LoRaWANInterface.cpp index 377d5279d2..f0f19f5b55 100644 --- a/features/lorawan/LoRaWANInterface.cpp +++ b/features/lorawan/LoRaWANInterface.cpp @@ -23,14 +23,9 @@ using namespace events; -inline LoRaWANStack& stk_obj() -{ - return LoRaWANStack::get_lorawan_stack(); -} - LoRaWANInterface::LoRaWANInterface(LoRaRadio& radio) { - stk_obj().bind_radio_driver(radio); + _lw_stack.bind_radio_driver(radio); } LoRaWANInterface::~LoRaWANInterface() @@ -39,95 +34,95 @@ LoRaWANInterface::~LoRaWANInterface() lorawan_status_t LoRaWANInterface::initialize(EventQueue *queue) { - return stk_obj().initialize_mac_layer(queue); + return _lw_stack.initialize_mac_layer(queue); } lorawan_status_t LoRaWANInterface::connect() { - return stk_obj().connect(); + return _lw_stack.connect(); } lorawan_status_t LoRaWANInterface::connect(const lorawan_connect_t &connect) { - return stk_obj().connect(connect); + return _lw_stack.connect(connect); } lorawan_status_t LoRaWANInterface::disconnect() { - return stk_obj().shutdown(); + return _lw_stack.shutdown(); } lorawan_status_t LoRaWANInterface::add_link_check_request() { - return stk_obj().set_link_check_request(); + return _lw_stack.set_link_check_request(); } void LoRaWANInterface::remove_link_check_request() { - stk_obj().remove_link_check_request(); + _lw_stack.remove_link_check_request(); } lorawan_status_t LoRaWANInterface::set_datarate(uint8_t data_rate) { - return stk_obj().set_channel_data_rate(data_rate); + return _lw_stack.set_channel_data_rate(data_rate); } lorawan_status_t LoRaWANInterface::set_confirmed_msg_retries(uint8_t count) { - return stk_obj().set_confirmed_msg_retry(count); + return _lw_stack.set_confirmed_msg_retry(count); } lorawan_status_t LoRaWANInterface::enable_adaptive_datarate() { - return stk_obj().enable_adaptive_datarate(true); + return _lw_stack.enable_adaptive_datarate(true); } lorawan_status_t LoRaWANInterface::disable_adaptive_datarate() { - return stk_obj().enable_adaptive_datarate(false); + return _lw_stack.enable_adaptive_datarate(false); } lorawan_status_t LoRaWANInterface::set_channel_plan(const lorawan_channelplan_t &channel_plan) { - return stk_obj().add_channels(channel_plan); + return _lw_stack.add_channels(channel_plan); } lorawan_status_t LoRaWANInterface::get_channel_plan(lorawan_channelplan_t &channel_plan) { - return stk_obj().get_enabled_channels(channel_plan); + return _lw_stack.get_enabled_channels(channel_plan); } lorawan_status_t LoRaWANInterface::remove_channel(uint8_t id) { - return stk_obj().remove_a_channel(id); + return _lw_stack.remove_a_channel(id); } lorawan_status_t LoRaWANInterface::remove_channel_plan() { - return stk_obj().drop_channel_list(); + return _lw_stack.drop_channel_list(); } int16_t LoRaWANInterface::send(uint8_t port, const uint8_t* data, uint16_t length, int flags) { - return stk_obj().handle_tx(port, data, length, flags); + return _lw_stack.handle_tx(port, data, length, flags); } int16_t LoRaWANInterface::receive(uint8_t port, uint8_t* data, uint16_t length, int flags) { - return stk_obj().handle_rx(data, length, port, flags, true); + return _lw_stack.handle_rx(data, length, port, flags, true); } int16_t LoRaWANInterface::receive(uint8_t* data, uint16_t length, uint8_t& port, int& flags) { - return stk_obj().handle_rx(data, length, port, flags, false); + return _lw_stack.handle_rx(data, length, port, flags, false); } lorawan_status_t LoRaWANInterface::add_app_callbacks(lorawan_app_callbacks_t *callbacks) { - return stk_obj().set_lora_callbacks(callbacks); + return _lw_stack.set_lora_callbacks(callbacks); } lorawan_status_t LoRaWANInterface::set_device_class(const device_class_t device_class) { - return stk_obj().set_device_class(device_class); + return _lw_stack.set_device_class(device_class); } diff --git a/features/lorawan/LoRaWANInterface.h b/features/lorawan/LoRaWANInterface.h index 03250ec483..87bdad12a2 100644 --- a/features/lorawan/LoRaWANInterface.h +++ b/features/lorawan/LoRaWANInterface.h @@ -434,6 +434,9 @@ public: * or other negative error code if request failed. */ virtual lorawan_status_t set_device_class(const device_class_t device_class); + +private: + LoRaWANStack _lw_stack; }; #endif /* LORAWANINTERFACE_H_ */ diff --git a/features/lorawan/LoRaWANStack.cpp b/features/lorawan/LoRaWANStack.cpp index f62e5294bd..fc0b68fe38 100644 --- a/features/lorawan/LoRaWANStack.cpp +++ b/features/lorawan/LoRaWANStack.cpp @@ -103,19 +103,9 @@ LoRaWANStack::LoRaWANStack() LoRaMacPrimitives.mlme_indication = callback(this, &LoRaWANStack::mlme_indication_handler); } -LoRaWANStack::~LoRaWANStack() -{ -} - /***************************************************************************** * Public member functions * ****************************************************************************/ -LoRaWANStack& LoRaWANStack::get_lorawan_stack() -{ - static LoRaWANStack _lw_stack; - return _lw_stack; -} - void LoRaWANStack::bind_radio_driver(LoRaRadio& radio) { _loramac.bind_radio_driver(radio); diff --git a/features/lorawan/LoRaWANStack.h b/features/lorawan/LoRaWANStack.h index baa2d828e5..5bc311e112 100644 --- a/features/lorawan/LoRaWANStack.h +++ b/features/lorawan/LoRaWANStack.h @@ -70,7 +70,7 @@ private: } device_states_t; public: - static LoRaWANStack& get_lorawan_stack(); + LoRaWANStack(); /** Binds radio driver to PHY layer. * @@ -396,9 +396,6 @@ public: lorawan_status_t set_device_class(const device_class_t& device_class); private: - LoRaWANStack(); - ~LoRaWANStack(); - /** * Checks if the user provided port is valid or not */ @@ -465,7 +462,6 @@ private: void send_automatic_uplink_message(const uint8_t port); private: - LoRaMac _loramac; loramac_primitives_t LoRaMacPrimitives; diff --git a/features/lorawan/lorastack/mac/LoRaMac.cpp b/features/lorawan/lorastack/mac/LoRaMac.cpp index eb11f05a4a..dfb09af45a 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.cpp +++ b/features/lorawan/lorastack/mac/LoRaMac.cpp @@ -24,7 +24,6 @@ SPDX-License-Identifier: BSD-3-Clause #include #include "LoRaMac.h" -#include "LoRaMacCrypto.h" #if defined(FEATURE_COMMON_PAL) #include "mbed_trace.h" @@ -37,6 +36,13 @@ SPDX-License-Identifier: BSD-3-Clause using namespace events; + +/* + * LoRaWAN spec 6.2: AppKey is AES-128 key + */ +#define APPKEY_KEY_LENGTH 128 + + /*! * Maximum length of the fOpts field */ @@ -311,17 +317,22 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, return; } - if (0 != decrypt_join_frame(payload + 1, size - 1, - _params.keys.app_key, - _params.payload + 1)) { + if (0 != _lora_crypto.decrypt_join_frame(payload + 1, + size - 1, + _params.keys.app_key, + APPKEY_KEY_LENGTH, + _params.payload + 1)) { _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; return; } _params.payload[0] = mac_hdr.value; - if (0 != compute_join_frame_mic(_params.payload, size - LORAMAC_MFR_LEN, - _params.keys.app_key, &mic)) { + if (0 != _lora_crypto.compute_join_frame_mic(_params.payload, + size - LORAMAC_MFR_LEN, + _params.keys.app_key, + APPKEY_KEY_LENGTH, + &mic)) { _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; return; } @@ -333,11 +344,12 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (mic_rx == mic) { - if (0 != compute_skeys_for_join_frame(_params.keys.app_key, - _params.payload + 1, - _params.dev_nonce, - _params.keys.nwk_skey, - _params.keys.app_skey)) { + if (0 != _lora_crypto.compute_skeys_for_join_frame(_params.keys.app_key, + APPKEY_KEY_LENGTH, + _params.payload + 1, + _params.dev_nonce, + _params.keys.nwk_skey, + _params.keys.app_skey)) { _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; return; } @@ -436,15 +448,17 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (sequence_counter_diff < (1 << 15)) { downlink_counter += sequence_counter_diff; - compute_mic(payload, size - LORAMAC_MFR_LEN, nwk_skey, - address, DOWN_LINK, downlink_counter, &mic); + _lora_crypto.compute_mic(payload, size - LORAMAC_MFR_LEN, + nwk_skey, sizeof(_params.keys.nwk_skey)*8, // sizeof nws_skey must be the same as _params.keys.nwk_skey + address, DOWN_LINK, downlink_counter, &mic); if (mic_rx == mic) { is_mic_ok = true; } } else { uint32_t downlink_counter_tmp = downlink_counter + 0x10000 + (int16_t)sequence_counter_diff; - compute_mic(payload, size - LORAMAC_MFR_LEN, nwk_skey, - address, DOWN_LINK, downlink_counter_tmp, &mic); + _lora_crypto.compute_mic(payload, size - LORAMAC_MFR_LEN, + nwk_skey, sizeof(_params.keys.nwk_skey)*8, // sizeof nws_skey must be the same as _params.keys.nwk_skey + address, DOWN_LINK, downlink_counter_tmp, &mic); if (mic_rx == mic ) { is_mic_ok = true; @@ -539,13 +553,14 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, if (port == 0) { if (fctrl.bits.fopts_len == 0) { - if (0 != decrypt_payload(payload + app_payload_start_index, - frame_len, - nwk_skey, - address, - DOWN_LINK, - downlink_counter, - _params.payload)) { + if (0 != _lora_crypto.decrypt_payload(payload + app_payload_start_index, + frame_len, + nwk_skey, + sizeof(_params.keys.nwk_skey)*8, // sizeof nws_skey must be the same as _params.keys.nwk_skey + address, + DOWN_LINK, + downlink_counter, + _params.payload)) { _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; } @@ -575,13 +590,14 @@ void LoRaMac::on_radio_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, } } - if (0 != decrypt_payload(payload + app_payload_start_index, - frame_len, - app_skey, - address, - DOWN_LINK, - downlink_counter, - _params.payload)) { + if (0 != _lora_crypto.decrypt_payload(payload + app_payload_start_index, + frame_len, + app_skey, + sizeof(_params.keys.app_skey)*8, // sizeof app_skey must be the same as _params.keys.app_skey + address, + DOWN_LINK, + downlink_counter, + _params.payload)) { _mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL; } @@ -1563,9 +1579,11 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, _params.buffer[_params.buffer_pkt_len++] = _params.dev_nonce & 0xFF; _params.buffer[_params.buffer_pkt_len++] = (_params.dev_nonce >> 8) & 0xFF; - if (0 != compute_join_frame_mic(_params.buffer, - _params.buffer_pkt_len & 0xFF, - _params.keys.app_key, &mic)) { + if (0 != _lora_crypto.compute_join_frame_mic(_params.buffer, + _params.buffer_pkt_len & 0xFF, + _params.keys.app_key, + APPKEY_KEY_LENGTH, + &mic)) { return LORAWAN_STATUS_CRYPTO_FAIL; } @@ -1646,23 +1664,27 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr, _params.buffer[pkt_header_len++] = frame_port; uint8_t *key = _params.keys.app_skey; + uint32_t key_length = sizeof(_params.keys.app_skey)*8; if (frame_port == 0) { mac_commands.clear_command_buffer(); key = _params.keys.nwk_skey; + key_length = sizeof(_params.keys.nwk_skey)*8; } - if (0 != encrypt_payload((uint8_t*) payload, _params.payload_length, - key, _params.dev_addr, UP_LINK, - _params.ul_frame_counter, - &_params.buffer[pkt_header_len])) { + if (0 != _lora_crypto.encrypt_payload((uint8_t*) payload, _params.payload_length, + key, key_length, + _params.dev_addr, UP_LINK, + _params.ul_frame_counter, + &_params.buffer[pkt_header_len])) { status = LORAWAN_STATUS_CRYPTO_FAIL; } } _params.buffer_pkt_len = pkt_header_len + _params.payload_length; - if (0 != compute_mic(_params.buffer, _params.buffer_pkt_len, - _params.keys.nwk_skey, _params.dev_addr, - UP_LINK, _params.ul_frame_counter, &mic)) { + if (0 != _lora_crypto.compute_mic(_params.buffer, _params.buffer_pkt_len, + _params.keys.nwk_skey, sizeof(_params.keys.nwk_skey)*8, + _params.dev_addr, + UP_LINK, _params.ul_frame_counter, &mic)) { status = LORAWAN_STATUS_CRYPTO_FAIL; } diff --git a/features/lorawan/lorastack/mac/LoRaMac.h b/features/lorawan/lorastack/mac/LoRaMac.h index f158af6e7f..04c5f00b72 100644 --- a/features/lorawan/lorastack/mac/LoRaMac.h +++ b/features/lorawan/lorastack/mac/LoRaMac.h @@ -50,6 +50,8 @@ #include "LoRaMacChannelPlan.h" #include "LoRaMacCommand.h" +#include "LoRaMacCrypto.h" + class LoRaMac { @@ -542,6 +544,11 @@ private: */ LoRaMacChannelPlan channel_plan; + /** + * Crypto handling subsystem + */ + LoRaMacCrypto _lora_crypto; + /** * Central MAC layer data storage */ diff --git a/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp b/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp index 73f73fa5a0..d2be171e01 100644 --- a/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp +++ b/features/lorawan/lorastack/mac/LoRaMacCrypto.cpp @@ -26,59 +26,27 @@ #include #include -#include "mbedtls/aes.h" -#include "mbedtls/cmac.h" - #include "LoRaMacCrypto.h" #include "system/lorawan_data_structures.h" #if defined(MBEDTLS_CMAC_C) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_CIPHER_C) -/** - * CMAC/AES Message Integrity Code (MIC) Block B0 size - */ -#define LORAMAC_MIC_BLOCK_B0_SIZE 16 - -/** - * MIC field computation initial data - */ -static uint8_t mic_block_b0[] = {0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -/** - * Contains the computed MIC field. - * - * \remark Only the 4 first bytes are used - */ -static uint8_t computed_mic[16]; - -/** - * Encryption aBlock and sBlock - */ -static uint8_t a_block[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static uint8_t s_block[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -/** - * AES computation context variable - */ -static mbedtls_aes_context aes_ctx; - -/** - * CMAC computation context variable - */ -static mbedtls_cipher_context_t aes_cmac_ctx[1]; - -#define AES_CMAC_KEY_LENGTH 16 - -int compute_mic(const uint8_t *buffer, uint16_t size, const uint8_t *key, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint32_t *mic) +LoRaMacCrypto::LoRaMacCrypto() + : mic_block_b0(), + computed_mic(), + a_block(), + s_block() { + mic_block_b0[0] = 0x49; + a_block[0] = 0x01; +} +int LoRaMacCrypto::compute_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, const uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint32_t *mic) +{ int ret = 0; mic_block_b0[5] = dir; @@ -104,13 +72,11 @@ int compute_mic(const uint8_t *buffer, uint16_t size, const uint8_t *key, if (0 != ret) goto exit; - ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, - AES_CMAC_KEY_LENGTH * 8); + ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, key_length); if (0 != ret) goto exit; - ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, mic_block_b0, - LORAMAC_MIC_BLOCK_B0_SIZE); + ret = mbedtls_cipher_cmac_update(aes_cmac_ctx, mic_block_b0, sizeof(mic_block_b0)); if (0 != ret) goto exit; @@ -133,9 +99,10 @@ exit: mbedtls_cipher_free(aes_cmac_ctx); return ret; } -int encrypt_payload(const uint8_t *buffer, uint16_t size, const uint8_t *key, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *enc_buffer) +int LoRaMacCrypto::encrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, const uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *enc_buffer) { uint16_t i; uint8_t bufferIndex = 0; @@ -143,7 +110,7 @@ int encrypt_payload(const uint8_t *buffer, uint16_t size, const uint8_t *key, int ret = 0; mbedtls_aes_init(&aes_ctx); - ret = mbedtls_aes_setkey_enc(&aes_ctx, key, 16 * 8); + ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); if (0 != ret) goto exit; @@ -190,16 +157,18 @@ exit: mbedtls_aes_free(&aes_ctx); return ret; } -int decrypt_payload(const uint8_t *buffer, uint16_t size, const uint8_t *key, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *dec_buffer) +int LoRaMacCrypto::decrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *dec_buffer) { - return encrypt_payload(buffer, size, key, address, dir, seq_counter, + return encrypt_payload(buffer, size, key, key_length, address, dir, seq_counter, dec_buffer); } -int compute_join_frame_mic(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t *mic) +int LoRaMacCrypto::compute_join_frame_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t *mic) { int ret = 0; @@ -211,8 +180,7 @@ int compute_join_frame_mic(const uint8_t *buffer, uint16_t size, if (0 != ret) goto exit; - ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, - AES_CMAC_KEY_LENGTH * 8); + ret = mbedtls_cipher_cmac_starts(aes_cmac_ctx, key, key_length); if (0 != ret) goto exit; @@ -235,14 +203,15 @@ exit: mbedtls_cipher_free(aes_cmac_ctx); return ret; } -int decrypt_join_frame(const uint8_t *buffer, uint16_t size, const uint8_t *key, - uint8_t *dec_buffer) +int LoRaMacCrypto::decrypt_join_frame(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint8_t *dec_buffer) { int ret = 0; mbedtls_aes_init(&aes_ctx); - ret = mbedtls_aes_setkey_enc(&aes_ctx, key, 16 * 8); + ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); if (0 != ret) goto exit; @@ -261,9 +230,9 @@ exit: mbedtls_aes_free(&aes_ctx); return ret; } -int compute_skeys_for_join_frame(const uint8_t *key, const uint8_t *app_nonce, - uint16_t dev_nonce, uint8_t *nwk_skey, - uint8_t *app_skey) +int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length, + const uint8_t *app_nonce, uint16_t dev_nonce, + uint8_t *nwk_skey, uint8_t *app_skey) { uint8_t nonce[16]; uint8_t *p_dev_nonce = (uint8_t *) &dev_nonce; @@ -271,7 +240,7 @@ int compute_skeys_for_join_frame(const uint8_t *key, const uint8_t *app_nonce, mbedtls_aes_init(&aes_ctx); - ret = mbedtls_aes_setkey_enc(&aes_ctx, key, 16 * 8); + ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length); if (0 != ret) goto exit; @@ -294,12 +263,17 @@ int compute_skeys_for_join_frame(const uint8_t *key, const uint8_t *app_nonce, } #else +LoRaMacCrypto::LoRaMacCrypto() +{ + MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); +} + // If mbedTLS is not configured properly, these dummies will ensure that // user knows what is wrong and in addition to that these ensure that // Mbed-OS compiles properly under normal conditions where LoRaWAN in conjunction // with mbedTLS is not being used. -int compute_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t, - uint8_t dir, uint32_t, uint32_t *) +int LoRaMacCrypto::compute_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t, uint32_t, + uint8_t dir, uint32_t, uint32_t *) { MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); @@ -307,8 +281,8 @@ int compute_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t, return LORAWAN_STATUS_CRYPTO_FAIL; } -int encrypt_payload(const uint8_t *, uint16_t , const uint8_t *, uint32_t, - uint8_t , uint32_t , uint8_t *) +int LoRaMacCrypto::encrypt_payload(const uint8_t *, uint16_t , const uint8_t *, uint32_t, uint32_t, + uint8_t , uint32_t , uint8_t *) { MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); @@ -316,8 +290,8 @@ int encrypt_payload(const uint8_t *, uint16_t , const uint8_t *, uint32_t, return LORAWAN_STATUS_CRYPTO_FAIL; } -int decrypt_payload(const uint8_t *, uint16_t , const uint8_t *, uint32_t, - uint8_t , uint32_t , uint8_t *) +int LoRaMacCrypto::decrypt_payload(const uint8_t *, uint16_t , const uint8_t *, uint32_t, uint32_t, + uint8_t , uint32_t , uint8_t *) { MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); @@ -325,7 +299,7 @@ int decrypt_payload(const uint8_t *, uint16_t , const uint8_t *, uint32_t, return LORAWAN_STATUS_CRYPTO_FAIL; } -int compute_join_frame_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t *) +int LoRaMacCrypto::compute_join_frame_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t, uint32_t *) { MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); @@ -333,7 +307,7 @@ int compute_join_frame_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t return LORAWAN_STATUS_CRYPTO_FAIL; } -int decrypt_join_frame(const uint8_t *, uint16_t , const uint8_t *, uint8_t *) +int LoRaMacCrypto::decrypt_join_frame(const uint8_t *, uint16_t , const uint8_t *, uint32_t, uint8_t *) { MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); @@ -341,8 +315,8 @@ int decrypt_join_frame(const uint8_t *, uint16_t , const uint8_t *, uint8_t *) return LORAWAN_STATUS_CRYPTO_FAIL; } -int compute_skeys_for_join_frame(const uint8_t *, const uint8_t *, uint16_t , - uint8_t *, uint8_t *) +int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *, uint32_t, const uint8_t *, uint16_t , + uint8_t *, uint8_t *) { MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS"); diff --git a/features/lorawan/lorastack/mac/LoRaMacCrypto.h b/features/lorawan/lorastack/mac/LoRaMacCrypto.h index af3fa75cff..b74729280e 100644 --- a/features/lorawan/lorastack/mac/LoRaMacCrypto.h +++ b/features/lorawan/lorastack/mac/LoRaMacCrypto.h @@ -1,4 +1,6 @@ /** +\code + / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ @@ -11,6 +13,8 @@ |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| embedded.connectivity.solutions=============== +\endcode + Description: LoRa MAC Crypto implementation License: Revised BSD License, see LICENSE.TXT file include in the project @@ -26,97 +30,150 @@ SPDX-License-Identifier: BSD-3-Clause #ifndef MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ #define MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ -/** - * Computes the LoRaMAC frame MIC field - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] address - Frame address - * @param [in] dir - Frame direction [0: uplink, 1: downlink] - * @param [in] seq_counter - Frame sequence counter - * @param [out] mic - Computed MIC field - * - * @return 0 if successful, or a cipher specific error code - */ -int compute_mic(const uint8_t *buffer, uint16_t size, const uint8_t *key, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint32_t *mic); +#include "mbedtls/aes.h" +#include "mbedtls/cmac.h" -/** - * Performs payload encryption - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] address - Frame address - * @param [in] dir - Frame direction [0: uplink, 1: downlink] - * @param [in] seq_counter - Frame sequence counter - * @param [out] enc_buffer - Encrypted buffer - * - * @return 0 if successful, or a cipher specific error code - */ -int encrypt_payload(const uint8_t *buffer, uint16_t size, const uint8_t *key, + +class LoRaMacCrypto +{ +public: + /** + * Constructor + */ + LoRaMacCrypto(); + + /** + * Computes the LoRaMAC frame MIC field + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] address - Frame address + * @param [in] dir - Frame direction [0: uplink, 1: downlink] + * @param [in] seq_counter - Frame sequence counter + * @param [out] mic - Computed MIC field + * + * @return 0 if successful, or a cipher specific error code + */ + int compute_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *enc_buffer); + uint32_t *mic); -/** - * Performs payload decryption - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [in] address - Frame address - * @param [in] dir - Frame direction [0: uplink, 1: downlink] - * @param [in] seq_counter - Frame sequence counter - * @param [out] dec_buffer - Decrypted buffer - * - * @return 0 if successful, or a cipher specific error code - */ -int decrypt_payload(const uint8_t *buffer, uint16_t size, const uint8_t *key, - uint32_t address, uint8_t dir, uint32_t seq_counter, - uint8_t *dec_buffer); + /** + * Performs payload encryption + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] address - Frame address + * @param [in] dir - Frame direction [0: uplink, 1: downlink] + * @param [in] seq_counter - Frame sequence counter + * @param [out] enc_buffer - Encrypted buffer + * + * @return 0 if successful, or a cipher specific error code + */ + int encrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *enc_buffer); -/** - * Computes the LoRaMAC Join Request frame MIC field - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [out] mic - Computed MIC field - * - * @return 0 if successful, or a cipher specific error code - * - */ -int compute_join_frame_mic(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint32_t *mic); + /** + * Performs payload decryption + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] address - Frame address + * @param [in] dir - Frame direction [0: uplink, 1: downlink] + * @param [in] seq_counter - Frame sequence counter + * @param [out] dec_buffer - Decrypted buffer + * + * @return 0 if successful, or a cipher specific error code + */ + int decrypt_payload(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t address, uint8_t dir, uint32_t seq_counter, + uint8_t *dec_buffer); -/** - * Computes the LoRaMAC join frame decryption - * - * @param [in] buffer - Data buffer - * @param [in] size - Data buffer size - * @param [in] key - AES key to be used - * @param [out] dec_buffer - Decrypted buffer - * - * @return 0 if successful, or a cipher specific error code - */ -int decrypt_join_frame(const uint8_t *buffer, uint16_t size, - const uint8_t *key, uint8_t *dec_buffer); + /** + * Computes the LoRaMAC Join Request frame MIC field + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [out] mic - Computed MIC field + * + * @return 0 if successful, or a cipher specific error code + * + */ + int compute_join_frame_mic(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint32_t *mic); -/** - * Computes the LoRaMAC join frame decryption - * - * @param [in] key - AES key to be used - * @param [in] app_nonce - Application nonce - * @param [in] dev_nonce - Device nonce - * @param [out] nwk_skey - Network session key - * @param [out] app_skey - Application session key - * - * @return 0 if successful, or a cipher specific error code - */ -int compute_skeys_for_join_frame(const uint8_t *key, const uint8_t *app_nonce, - uint16_t dev_nonce, uint8_t *nwk_skey, - uint8_t *app_skey ); + /** + * Computes the LoRaMAC join frame decryption + * + * @param [in] buffer - Data buffer + * @param [in] size - Data buffer size + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [out] dec_buffer - Decrypted buffer + * + * @return 0 if successful, or a cipher specific error code + */ + int decrypt_join_frame(const uint8_t *buffer, uint16_t size, + const uint8_t *key, uint32_t key_length, + uint8_t *dec_buffer); + + /** + * Computes the LoRaMAC join frame decryption + * + * @param [in] key - AES key to be used + * @param [in] key_length - Length of the key (bits) + * @param [in] app_nonce - Application nonce + * @param [in] dev_nonce - Device nonce + * @param [out] nwk_skey - Network session key + * @param [out] app_skey - Application session key + * + * @return 0 if successful, or a cipher specific error code + */ + int compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length, + const uint8_t *app_nonce, uint16_t dev_nonce, + uint8_t *nwk_skey, uint8_t *app_skey); + +private: + /** + * MIC field computation initial data + */ + uint8_t mic_block_b0[16]; + + /** + * Contains the computed MIC field. + * + * \remark Only the 4 first bytes are used + */ + uint8_t computed_mic[16]; + + /** + * Encryption aBlock and sBlock + */ + uint8_t a_block[16]; + uint8_t s_block[16]; + + /** + * AES computation context variable + */ + mbedtls_aes_context aes_ctx; + + /** + * CMAC computation context variable + */ + mbedtls_cipher_context_t aes_cmac_ctx[1]; +}; #endif // MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__ diff --git a/features/lorawan/system/lorawan_data_structures.h b/features/lorawan/system/lorawan_data_structures.h index 381082418c..7c1e9fd03e 100644 --- a/features/lorawan/system/lorawan_data_structures.h +++ b/features/lorawan/system/lorawan_data_structures.h @@ -1244,11 +1244,13 @@ typedef struct { /*! * AES encryption/decryption cipher network session key + * NOTE! LoRaMac determines the length of the key based on sizeof this variable */ uint8_t nwk_skey[16]; /*! * AES encryption/decryption cipher application session key + * NOTE! LoRaMac determines the length of the key based on sizeof this variable */ uint8_t app_skey[16];