Espotel
/
LoRaWAN_ELMO_TxRx_Template
Example Tx Rx LoRa code for Multitech Conduit. Based on Semtech stack for ELMO - ver. 4.1.0.
mac/LoRaMacCrypto.cpp@6:71b489e70063, 2016-04-19 (annotated)
- Committer:
- Pasi
- Date:
- Tue Apr 19 21:48:58 2016 +0000
- Revision:
- 6:71b489e70063
- Parent:
- 1:2be292bd43f9
Text tweaking
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mleksio | 0:c58229885f95 | 1 | /* |
mleksio | 0:c58229885f95 | 2 | / _____) _ | | |
mleksio | 0:c58229885f95 | 3 | ( (____ _____ ____ _| |_ _____ ____| |__ |
mleksio | 0:c58229885f95 | 4 | \____ \| ___ | (_ _) ___ |/ ___) _ \ |
mleksio | 0:c58229885f95 | 5 | _____) ) ____| | | || |_| ____( (___| | | | |
mleksio | 0:c58229885f95 | 6 | (______/|_____)_|_|_| \__)_____)\____)_| |_| |
mleksio | 0:c58229885f95 | 7 | (C)2013 Semtech |
mleksio | 1:2be292bd43f9 | 8 | ___ _____ _ ___ _ _____ ___ ___ ___ ___ |
mleksio | 1:2be292bd43f9 | 9 | / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| |
mleksio | 1:2be292bd43f9 | 10 | \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| |
mleksio | 1:2be292bd43f9 | 11 | |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| |
mleksio | 1:2be292bd43f9 | 12 | embedded.connectivity.solutions=============== |
mleksio | 0:c58229885f95 | 13 | Description: LoRa MAC layer implementation |
mleksio | 0:c58229885f95 | 14 | License: Revised BSD License, see LICENSE.TXT file include in the project |
mleksio | 1:2be292bd43f9 | 15 | Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) |
mleksio | 0:c58229885f95 | 16 | */ |
mleksio | 0:c58229885f95 | 17 | #include <stdlib.h> |
mleksio | 0:c58229885f95 | 18 | #include <stdint.h> |
mleksio | 0:c58229885f95 | 19 | #include "utilities.h" |
mleksio | 0:c58229885f95 | 20 | |
mleksio | 0:c58229885f95 | 21 | #include "aes.h" |
mleksio | 0:c58229885f95 | 22 | #include "cmac.h" |
mleksio | 0:c58229885f95 | 23 | |
mleksio | 0:c58229885f95 | 24 | #include "LoRaMacCrypto.h" |
mleksio | 0:c58229885f95 | 25 | |
mleksio | 0:c58229885f95 | 26 | /*! |
mleksio | 0:c58229885f95 | 27 | * CMAC/AES Message Integrity Code (MIC) Block B0 size |
mleksio | 0:c58229885f95 | 28 | */ |
mleksio | 0:c58229885f95 | 29 | #define LORAMAC_MIC_BLOCK_B0_SIZE 16 |
mleksio | 0:c58229885f95 | 30 | |
mleksio | 0:c58229885f95 | 31 | /*! |
mleksio | 0:c58229885f95 | 32 | * MIC field computation initial data |
mleksio | 0:c58229885f95 | 33 | */ |
mleksio | 0:c58229885f95 | 34 | static uint8_t MicBlockB0[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
mleksio | 0:c58229885f95 | 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
mleksio | 0:c58229885f95 | 36 | }; |
mleksio | 0:c58229885f95 | 37 | |
mleksio | 0:c58229885f95 | 38 | /*! |
mleksio | 0:c58229885f95 | 39 | * Contains the computed MIC field. |
mleksio | 0:c58229885f95 | 40 | * |
mleksio | 0:c58229885f95 | 41 | * \remark Only the 4 first bytes are used |
mleksio | 0:c58229885f95 | 42 | */ |
mleksio | 0:c58229885f95 | 43 | static uint8_t Mic[16]; |
mleksio | 0:c58229885f95 | 44 | |
mleksio | 0:c58229885f95 | 45 | /*! |
mleksio | 0:c58229885f95 | 46 | * Encryption aBlock and sBlock |
mleksio | 0:c58229885f95 | 47 | */ |
mleksio | 0:c58229885f95 | 48 | static uint8_t aBlock[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
mleksio | 0:c58229885f95 | 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
mleksio | 0:c58229885f95 | 50 | }; |
mleksio | 0:c58229885f95 | 51 | static uint8_t sBlock[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
mleksio | 0:c58229885f95 | 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
mleksio | 0:c58229885f95 | 53 | }; |
mleksio | 0:c58229885f95 | 54 | |
mleksio | 0:c58229885f95 | 55 | /*! |
mleksio | 0:c58229885f95 | 56 | * AES computation context variable |
mleksio | 0:c58229885f95 | 57 | */ |
mleksio | 0:c58229885f95 | 58 | static aes_context AesContext; |
mleksio | 0:c58229885f95 | 59 | |
mleksio | 0:c58229885f95 | 60 | /*! |
mleksio | 0:c58229885f95 | 61 | * CMAC computation context variable |
mleksio | 0:c58229885f95 | 62 | */ |
mleksio | 0:c58229885f95 | 63 | static AES_CMAC_CTX AesCmacCtx[1]; |
mleksio | 0:c58229885f95 | 64 | |
mleksio | 0:c58229885f95 | 65 | /*! |
mleksio | 0:c58229885f95 | 66 | * \brief Computes the LoRaMAC frame MIC field |
mleksio | 0:c58229885f95 | 67 | * |
mleksio | 0:c58229885f95 | 68 | * \param [IN] buffer Data buffer |
mleksio | 0:c58229885f95 | 69 | * \param [IN] size Data buffer size |
mleksio | 0:c58229885f95 | 70 | * \param [IN] key AES key to be used |
mleksio | 0:c58229885f95 | 71 | * \param [IN] address Frame address |
mleksio | 0:c58229885f95 | 72 | * \param [IN] dir Frame direction [0: uplink, 1: downlink] |
mleksio | 0:c58229885f95 | 73 | * \param [IN] sequenceCounter Frame sequence counter |
mleksio | 0:c58229885f95 | 74 | * \param [OUT] mic Computed MIC field |
mleksio | 0:c58229885f95 | 75 | */ |
mleksio | 0:c58229885f95 | 76 | 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 ) |
mleksio | 0:c58229885f95 | 77 | { |
mleksio | 0:c58229885f95 | 78 | MicBlockB0[5] = dir; |
mleksio | 0:c58229885f95 | 79 | |
mleksio | 0:c58229885f95 | 80 | MicBlockB0[6] = ( address ) & 0xFF; |
mleksio | 0:c58229885f95 | 81 | MicBlockB0[7] = ( address >> 8 ) & 0xFF; |
mleksio | 0:c58229885f95 | 82 | MicBlockB0[8] = ( address >> 16 ) & 0xFF; |
mleksio | 0:c58229885f95 | 83 | MicBlockB0[9] = ( address >> 24 ) & 0xFF; |
mleksio | 0:c58229885f95 | 84 | |
mleksio | 0:c58229885f95 | 85 | MicBlockB0[10] = ( sequenceCounter ) & 0xFF; |
mleksio | 0:c58229885f95 | 86 | MicBlockB0[11] = ( sequenceCounter >> 8 ) & 0xFF; |
mleksio | 0:c58229885f95 | 87 | MicBlockB0[12] = ( sequenceCounter >> 16 ) & 0xFF; |
mleksio | 0:c58229885f95 | 88 | MicBlockB0[13] = ( sequenceCounter >> 24 ) & 0xFF; |
mleksio | 0:c58229885f95 | 89 | |
mleksio | 0:c58229885f95 | 90 | MicBlockB0[15] = size & 0xFF; |
mleksio | 0:c58229885f95 | 91 | |
mleksio | 0:c58229885f95 | 92 | AES_CMAC_Init( AesCmacCtx ); |
mleksio | 0:c58229885f95 | 93 | |
mleksio | 0:c58229885f95 | 94 | AES_CMAC_SetKey( AesCmacCtx, key ); |
mleksio | 0:c58229885f95 | 95 | |
mleksio | 0:c58229885f95 | 96 | AES_CMAC_Update( AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE ); |
mleksio | 0:c58229885f95 | 97 | |
mleksio | 0:c58229885f95 | 98 | AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF ); |
mleksio | 0:c58229885f95 | 99 | |
mleksio | 0:c58229885f95 | 100 | AES_CMAC_Final( Mic, AesCmacCtx ); |
mleksio | 0:c58229885f95 | 101 | |
mleksio | 0:c58229885f95 | 102 | *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] ); |
mleksio | 0:c58229885f95 | 103 | } |
mleksio | 0:c58229885f95 | 104 | |
mleksio | 0:c58229885f95 | 105 | 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 ) |
mleksio | 0:c58229885f95 | 106 | { |
mleksio | 0:c58229885f95 | 107 | uint16_t i; |
mleksio | 0:c58229885f95 | 108 | uint8_t bufferIndex = 0; |
mleksio | 0:c58229885f95 | 109 | uint16_t ctr = 1; |
mleksio | 0:c58229885f95 | 110 | |
mleksio | 0:c58229885f95 | 111 | memset1( AesContext.ksch, '\0', 240 ); |
mleksio | 0:c58229885f95 | 112 | aes_set_key( key, 16, &AesContext ); |
mleksio | 0:c58229885f95 | 113 | |
mleksio | 0:c58229885f95 | 114 | aBlock[5] = dir; |
mleksio | 0:c58229885f95 | 115 | |
mleksio | 0:c58229885f95 | 116 | aBlock[6] = ( address ) & 0xFF; |
mleksio | 0:c58229885f95 | 117 | aBlock[7] = ( address >> 8 ) & 0xFF; |
mleksio | 0:c58229885f95 | 118 | aBlock[8] = ( address >> 16 ) & 0xFF; |
mleksio | 0:c58229885f95 | 119 | aBlock[9] = ( address >> 24 ) & 0xFF; |
mleksio | 0:c58229885f95 | 120 | |
mleksio | 0:c58229885f95 | 121 | aBlock[10] = ( sequenceCounter ) & 0xFF; |
mleksio | 0:c58229885f95 | 122 | aBlock[11] = ( sequenceCounter >> 8 ) & 0xFF; |
mleksio | 0:c58229885f95 | 123 | aBlock[12] = ( sequenceCounter >> 16 ) & 0xFF; |
mleksio | 0:c58229885f95 | 124 | aBlock[13] = ( sequenceCounter >> 24 ) & 0xFF; |
mleksio | 0:c58229885f95 | 125 | |
mleksio | 0:c58229885f95 | 126 | while( size >= 16 ) |
mleksio | 0:c58229885f95 | 127 | { |
mleksio | 0:c58229885f95 | 128 | aBlock[15] = ( ( ctr ) & 0xFF ); |
mleksio | 0:c58229885f95 | 129 | ctr++; |
mleksio | 0:c58229885f95 | 130 | aes_encrypt( aBlock, sBlock, &AesContext ); |
mleksio | 0:c58229885f95 | 131 | for( i = 0; i < 16; i++ ) |
mleksio | 0:c58229885f95 | 132 | { |
mleksio | 0:c58229885f95 | 133 | encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; |
mleksio | 0:c58229885f95 | 134 | } |
mleksio | 0:c58229885f95 | 135 | size -= 16; |
mleksio | 0:c58229885f95 | 136 | bufferIndex += 16; |
mleksio | 0:c58229885f95 | 137 | } |
mleksio | 0:c58229885f95 | 138 | |
mleksio | 0:c58229885f95 | 139 | if( size > 0 ) |
mleksio | 0:c58229885f95 | 140 | { |
mleksio | 0:c58229885f95 | 141 | aBlock[15] = ( ( ctr ) & 0xFF ); |
mleksio | 0:c58229885f95 | 142 | aes_encrypt( aBlock, sBlock, &AesContext ); |
mleksio | 0:c58229885f95 | 143 | for( i = 0; i < size; i++ ) |
mleksio | 0:c58229885f95 | 144 | { |
mleksio | 0:c58229885f95 | 145 | encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; |
mleksio | 0:c58229885f95 | 146 | } |
mleksio | 0:c58229885f95 | 147 | } |
mleksio | 0:c58229885f95 | 148 | } |
mleksio | 0:c58229885f95 | 149 | |
mleksio | 0:c58229885f95 | 150 | 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 ) |
mleksio | 0:c58229885f95 | 151 | { |
mleksio | 0:c58229885f95 | 152 | LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer ); |
mleksio | 0:c58229885f95 | 153 | } |
mleksio | 0:c58229885f95 | 154 | |
mleksio | 0:c58229885f95 | 155 | void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic ) |
mleksio | 0:c58229885f95 | 156 | { |
mleksio | 0:c58229885f95 | 157 | AES_CMAC_Init( AesCmacCtx ); |
mleksio | 0:c58229885f95 | 158 | |
mleksio | 0:c58229885f95 | 159 | AES_CMAC_SetKey( AesCmacCtx, key ); |
mleksio | 0:c58229885f95 | 160 | |
mleksio | 0:c58229885f95 | 161 | AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF ); |
mleksio | 0:c58229885f95 | 162 | |
mleksio | 0:c58229885f95 | 163 | AES_CMAC_Final( Mic, AesCmacCtx ); |
mleksio | 0:c58229885f95 | 164 | |
mleksio | 0:c58229885f95 | 165 | *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] ); |
mleksio | 0:c58229885f95 | 166 | } |
mleksio | 0:c58229885f95 | 167 | |
mleksio | 0:c58229885f95 | 168 | void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer ) |
mleksio | 0:c58229885f95 | 169 | { |
mleksio | 0:c58229885f95 | 170 | memset1( AesContext.ksch, '\0', 240 ); |
mleksio | 0:c58229885f95 | 171 | aes_set_key( key, 16, &AesContext ); |
mleksio | 0:c58229885f95 | 172 | aes_encrypt( buffer, decBuffer, &AesContext ); |
mleksio | 0:c58229885f95 | 173 | // Check if optional CFList is included |
mleksio | 0:c58229885f95 | 174 | if( size >= 16 ) |
mleksio | 0:c58229885f95 | 175 | { |
mleksio | 0:c58229885f95 | 176 | aes_encrypt( buffer + 16, decBuffer + 16, &AesContext ); |
mleksio | 0:c58229885f95 | 177 | } |
mleksio | 0:c58229885f95 | 178 | } |
mleksio | 0:c58229885f95 | 179 | |
mleksio | 0:c58229885f95 | 180 | void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey ) |
mleksio | 0:c58229885f95 | 181 | { |
mleksio | 0:c58229885f95 | 182 | uint8_t nonce[16]; |
mleksio | 0:c58229885f95 | 183 | uint8_t *pDevNonce = ( uint8_t * )&devNonce; |
mleksio | 0:c58229885f95 | 184 | |
mleksio | 0:c58229885f95 | 185 | memset1( AesContext.ksch, '\0', 240 ); |
mleksio | 0:c58229885f95 | 186 | aes_set_key( key, 16, &AesContext ); |
mleksio | 0:c58229885f95 | 187 | |
mleksio | 0:c58229885f95 | 188 | memset1( nonce, 0, sizeof( nonce ) ); |
mleksio | 0:c58229885f95 | 189 | nonce[0] = 0x01; |
mleksio | 1:2be292bd43f9 | 190 | memcpy1( nonce + 1, appNonce, 6 ); |
mleksio | 1:2be292bd43f9 | 191 | memcpy1( nonce + 7, pDevNonce, 2 ); |
mleksio | 0:c58229885f95 | 192 | aes_encrypt( nonce, nwkSKey, &AesContext ); |
mleksio | 0:c58229885f95 | 193 | |
mleksio | 0:c58229885f95 | 194 | memset1( nonce, 0, sizeof( nonce ) ); |
mleksio | 0:c58229885f95 | 195 | nonce[0] = 0x02; |
mleksio | 1:2be292bd43f9 | 196 | memcpy1( nonce + 1, appNonce, 6 ); |
mleksio | 1:2be292bd43f9 | 197 | memcpy1( nonce + 7, pDevNonce, 2 ); |
mleksio | 0:c58229885f95 | 198 | aes_encrypt( nonce, appSKey, &AesContext ); |
mleksio | 0:c58229885f95 | 199 | } |