Simplified LoRaWAN library.
Fork of LoRaWAN-lib-v1_0_1 by
Diff: LoRaMacCrypto.cpp
- Revision:
- 0:91d1a7783bb9
- Child:
- 1:91e4e6c60d1e
diff -r 000000000000 -r 91d1a7783bb9 LoRaMacCrypto.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LoRaMacCrypto.cpp Tue Oct 20 13:21:26 2015 +0000 @@ -0,0 +1,197 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + +Description: LoRa MAC layer implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian +*/ +#include "mbed.h" +#include "board.h" +#include "utilities.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[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[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 ); + 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++; + 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 ); + 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 ); + aes_set_key( key, 16, &AesContext ); + aes_encrypt( buffer, decBuffer, &AesContext ); + // Check if optional CFList is included + if( size >= 16 ) + { + 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 ); + aes_set_key( key, 16, &AesContext ); + + memset1( nonce, 0, sizeof( nonce ) ); + nonce[0] = 0x01; + LoRaMacMemCpy( appNonce, nonce + 1, 6 ); + LoRaMacMemCpy( pDevNonce, nonce + 7, 2 ); + aes_encrypt( nonce, nwkSKey, &AesContext ); + + memset1( nonce, 0, sizeof( nonce ) ); + nonce[0] = 0x02; + LoRaMacMemCpy( appNonce, nonce + 1, 6 ); + LoRaMacMemCpy( pDevNonce, nonce + 7, 2 ); + aes_encrypt( nonce, appSKey, &AesContext ); +}