/* * Copyright (C) 2015-2017 Alibaba Group Holding Limited */ /* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (C)2013 Semtech ___ _____ _ ___ _ _____ ___ ___ ___ ___ / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| embedded.connectivity.solutions=============== Description: LoRa MAC layer implementation License: Revised BSD License, see LICENSE.TXT file include in the project Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE ) */ #include #include #include "cmacutil.h" #include "aes.h" #include "cmac.h" #include "LoRaMacCrypto.h" /*! * CMAC/AES Message Integrity Code (MIC) Block B0 size */ #define LORAMAC_MIC_BLOCK_B0_SIZE 16 /*! * MIC field computation initial data */ static uint8_t MicBlockB0[] = { 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 Mic[16]; /*! * Encryption aBlock and sBlock */ static uint8_t aBlock[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static uint8_t sBlock[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*! * AES computation context variable */ static aes_context AesContext; /*! * CMAC computation context variable */ static AES_CMAC_CTX AesCmacCtx[1]; /*! * \brief 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] sequenceCounter Frame sequence counter * \param [OUT] mic Computed MIC field */ void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic ) { MicBlockB0[0] = 0x49; // these are already preloade but you never know... MicBlockB0[1] = 0x00; MicBlockB0[2] = 0x00; MicBlockB0[3] = 0x00; MicBlockB0[4] = 0x00; MicBlockB0[5] = dir; MicBlockB0[6] = ( address ) & 0xFF; MicBlockB0[7] = ( address >> 8 ) & 0xFF; MicBlockB0[8] = ( address >> 16 ) & 0xFF; MicBlockB0[9] = ( address >> 24 ) & 0xFF; MicBlockB0[10] = ( sequenceCounter ) & 0xFF; MicBlockB0[11] = ( sequenceCounter >> 8 ) & 0xFF; MicBlockB0[12] = ( sequenceCounter >> 16 ) & 0xFF; MicBlockB0[13] = ( sequenceCounter >> 24 ) & 0xFF; MicBlockB0[14] = 0x00; // preloaded in principle, but ... MicBlockB0[15] = size & 0xFF; AES_CMAC_Init( AesCmacCtx ); AES_CMAC_SetKey( AesCmacCtx, key ); AES_CMAC_Update( AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE ); AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF ); AES_CMAC_Final( Mic, AesCmacCtx ); *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] ); } void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer ) { uint16_t i; uint8_t bufferIndex = 0; uint16_t ctr = 1; memset1( AesContext.ksch, '\0', 240 ); lorawan_aes_set_key( key, 16, &AesContext ); aBlock[5] = dir; aBlock[6] = ( address ) & 0xFF; aBlock[7] = ( address >> 8 ) & 0xFF; aBlock[8] = ( address >> 16 ) & 0xFF; aBlock[9] = ( address >> 24 ) & 0xFF; aBlock[10] = ( sequenceCounter ) & 0xFF; aBlock[11] = ( sequenceCounter >> 8 ) & 0xFF; aBlock[12] = ( sequenceCounter >> 16 ) & 0xFF; aBlock[13] = ( sequenceCounter >> 24 ) & 0xFF; while( size >= 16 ) { aBlock[15] = ( ( ctr ) & 0xFF ); ctr++; lora_aes_encrypt( aBlock, sBlock, &AesContext ); for( i = 0; i < 16; i++ ) { encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; } size -= 16; bufferIndex += 16; } if( size > 0 ) { aBlock[15] = ( ( ctr ) & 0xFF ); lora_aes_encrypt( aBlock, sBlock, &AesContext ); for( i = 0; i < size; i++ ) { encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; } } } void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer ) { LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer ); } void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic ) { AES_CMAC_Init( AesCmacCtx ); AES_CMAC_SetKey( AesCmacCtx, key ); AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF ); AES_CMAC_Final( Mic, AesCmacCtx ); *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] ); } void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer ) { memset1( AesContext.ksch, '\0', 240 ); lorawan_aes_set_key( key, 16, &AesContext ); lora_aes_encrypt( buffer, decBuffer, &AesContext ); // Check if optional CFList is included if( size >= 16 ) { lora_aes_encrypt( buffer + 16, decBuffer + 16, &AesContext ); } } void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey ) { uint8_t nonce[16]; uint8_t *pDevNonce = ( uint8_t * )&devNonce; memset1( AesContext.ksch, '\0', 240 ); lorawan_aes_set_key( key, 16, &AesContext ); memset1( nonce, 0, sizeof( nonce ) ); nonce[0] = 0x01; memcpy1( nonce + 1, appNonce, 6 ); memcpy1( nonce + 7, pDevNonce, 2 ); lora_aes_encrypt( nonce, nwkSKey, &AesContext ); memset1( nonce, 0, sizeof( nonce ) ); nonce[0] = 0x02; memcpy1( nonce + 1, appNonce, 6 ); memcpy1( nonce + 7, pDevNonce, 2 ); lora_aes_encrypt( nonce, appSKey, &AesContext ); } void LoRaMacBeaconComputePingOffset( uint64_t beaconTime, uint32_t address, uint16_t pingPeriod, uint16_t *pingOffset ) { uint8_t zeroKey[16]; uint8_t buffer[16]; uint8_t cipher[16]; uint32_t result = 0; /* Refer to chapter 15.2 of the LoRaWAN specification v1.1. The beacon time * GPS time in seconds modulo 2^32 */ uint32_t time = ( beaconTime % ( ( ( uint64_t ) 1 ) << 32 ) ); memset1( zeroKey, 0, 16 ); memset1( buffer, 0, 16 ); memset1( cipher, 0, 16 ); memset1( AesContext.ksch, '\0', 240 ); buffer[0] = ( time ) & 0xFF; buffer[1] = ( time >> 8 ) & 0xFF; buffer[2] = ( time >> 16 ) & 0xFF; buffer[3] = ( time >> 24 ) & 0xFF; buffer[4] = ( address ) & 0xFF; buffer[5] = ( address >> 8 ) & 0xFF; buffer[6] = ( address >> 16 ) & 0xFF; buffer[7] = ( address >> 24 ) & 0xFF; lorawan_aes_set_key( zeroKey, 16, &AesContext ); lora_aes_encrypt( buffer, cipher, &AesContext ); result = ( ( ( uint32_t ) cipher[0] ) + ( ( ( uint32_t ) cipher[1] ) * 256 ) ); *pingOffset = ( uint16_t )( result % pingPeriod ); }