1 /*!
2  * \file      LoRaMacCrypto.c
3  *
4  * \brief     LoRa MAC layer cryptography implementation
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2017 Semtech
16  *
17  *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
18  *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
19  *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
20  *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
21  *              embedded.connectivity.solutions===============
22  *
23  * \endcode
24  *
25  * \author    Miguel Luis ( Semtech )
26  *
27  * \author    Gregory Cristian ( Semtech )
28  *
29  * \author    Daniel Jaeckle ( STACKFORCE )
30  *
31  * \author    Johannes Bruder ( STACKFORCE )
32  */
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 
37 #include "utilities.h"
38 #include "secure-element.h"
39 
40 #include "LoRaMacParser.h"
41 #include "LoRaMacSerializer.h"
42 #include "LoRaMacCrypto.h"
43 
44 /*
45  * Frame direction definition for uplink communications
46  */
47 #define UPLINK                          0
48 
49 /*
50  * Frame direction definition for downlink communications
51  */
52 #define DOWNLINK                        1
53 
54 /*
55  * CMAC/AES Message Integrity Code (MIC) Block B0 size
56  */
57 #define MIC_BLOCK_BX_SIZE               16
58 
59 /*
60  * Number of security context entries
61  */
62 #define NUM_OF_SEC_CTX                  5
63 
64 /*
65  * Maximum size of the message that can be handled by the crypto operations
66  */
67 #define CRYPTO_MAXMESSAGE_SIZE          256
68 
69 /*
70  * Maximum size of the buffer for crypto operations
71  */
72 #define CRYPTO_BUFFER_SIZE              CRYPTO_MAXMESSAGE_SIZE + MIC_BLOCK_BX_SIZE
73 
74 /*
75  * Key-Address item
76  */
77 typedef struct sKeyAddr
78 {
79     /*
80      * Address identifier
81      */
82     AddressIdentifier_t AddrID;
83     /*
84      * Application session key
85      */
86     KeyIdentifier_t AppSkey;
87     /*
88      * Network session key
89      */
90     KeyIdentifier_t NwkSkey;
91     /*
92      * Rootkey (Multicast only)
93      */
94     KeyIdentifier_t RootKey;
95 }KeyAddr_t;
96 
97 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
98 /*
99  * RJcount0 is a counter incremented with every Type 0 or 2 Rejoin frame transmitted.
100  */
101 static uint16_t RJcount0;
102 #endif
103 
104 /*
105  * Non volatile module context.
106  */
107 static LoRaMacCryptoNvmData_t* CryptoNvm;
108 
109 /*
110  * Key-Address list
111  */
112 static KeyAddr_t KeyAddrList[NUM_OF_SEC_CTX] =
113     {
114         { MULTICAST_0_ADDR, MC_APP_S_KEY_0, MC_NWK_S_KEY_0, MC_KEY_0 },
115         { MULTICAST_1_ADDR, MC_APP_S_KEY_1, MC_NWK_S_KEY_1, MC_KEY_1 },
116         { MULTICAST_2_ADDR, MC_APP_S_KEY_2, MC_NWK_S_KEY_2, MC_KEY_2 },
117         { MULTICAST_3_ADDR, MC_APP_S_KEY_3, MC_NWK_S_KEY_3, MC_KEY_3 },
118         { UNICAST_DEV_ADDR, APP_S_KEY, S_NWK_S_INT_KEY, NO_KEY }
119     };
120 
121 /*
122  * Encrypts the payload
123  *
124  * \param[IN]  keyID            - Key identifier
125  * \param[IN]  address          - Address
126  * \param[IN]  dir              - Frame direction ( Uplink or Downlink )
127  * \param[IN]  frameCounter     - Frame counter
128  * \param[IN]  size             - Size of data
129  * \param[IN/OUT]  buffer       - Data buffer
130  * \retval                      - Status of the operation
131  */
PayloadEncrypt(uint8_t * buffer,int16_t size,KeyIdentifier_t keyID,uint32_t address,uint8_t dir,uint32_t frameCounter)132 static LoRaMacCryptoStatus_t PayloadEncrypt( uint8_t* buffer, int16_t size, KeyIdentifier_t keyID, uint32_t address, uint8_t dir, uint32_t frameCounter )
133 {
134     if( buffer == 0 )
135     {
136         return LORAMAC_CRYPTO_ERROR_NPE;
137     }
138 
139     uint8_t bufferIndex = 0;
140     uint16_t ctr = 1;
141     uint8_t sBlock[16] = { 0 };
142     uint8_t aBlock[16] = { 0 };
143 
144     aBlock[0] = 0x01;
145 
146     aBlock[5] = dir;
147 
148     aBlock[6] = address & 0xFF;
149     aBlock[7] = ( address >> 8 ) & 0xFF;
150     aBlock[8] = ( address >> 16 ) & 0xFF;
151     aBlock[9] = ( address >> 24 ) & 0xFF;
152 
153     aBlock[10] = frameCounter & 0xFF;
154     aBlock[11] = ( frameCounter >> 8 ) & 0xFF;
155     aBlock[12] = ( frameCounter >> 16 ) & 0xFF;
156     aBlock[13] = ( frameCounter >> 24 ) & 0xFF;
157 
158     while( size > 0 )
159     {
160         aBlock[15] = ctr & 0xFF;
161         ctr++;
162         if( SecureElementAesEncrypt( aBlock, 16, keyID, sBlock ) != SECURE_ELEMENT_SUCCESS )
163         {
164             return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
165         }
166 
167         for( uint8_t i = 0; i < ( ( size > 16 ) ? 16 : size ); i++ )
168         {
169             buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
170         }
171         size -= 16;
172         bufferIndex += 16;
173     }
174 
175     return LORAMAC_CRYPTO_SUCCESS;
176 }
177 
178 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
179 /*
180  * Encrypts the FOpts
181  *
182  * \param[IN]  address          - Address
183  * \param[IN]  dir              - Frame direction ( Uplink or Downlink )
184  * \param[IN]  fCntID           - Frame counter identifier
185  * \param[IN]  frameCounter     - Frame counter
186  * \param[IN]  size             - Size of data
187  * \param[IN/OUT]  buffer       - Data buffer
188  * \retval                      - Status of the operation
189  */
FOptsEncrypt(uint16_t size,uint32_t address,uint8_t dir,FCntIdentifier_t fCntID,uint32_t frameCounter,uint8_t * buffer)190 static LoRaMacCryptoStatus_t FOptsEncrypt( uint16_t size, uint32_t address, uint8_t dir, FCntIdentifier_t fCntID, uint32_t frameCounter, uint8_t* buffer )
191 {
192     if( buffer == 0 )
193     {
194         return LORAMAC_CRYPTO_ERROR_NPE;
195     }
196 
197     uint8_t bufferIndex = 0;
198     uint8_t sBlock[16] = { 0 };
199     uint8_t aBlock[16] = { 0 };
200 
201     aBlock[0] = 0x01;
202 
203     if( CryptoNvm->LrWanVersion.Value > 0x01010000 )
204     {
205         // Introduced in LoRaWAN 1.1.1 specification
206         switch( fCntID )
207         {
208             case FCNT_UP:
209             {
210                 aBlock[4] = 0x01;
211                 break;
212             }
213             case N_FCNT_DOWN:
214             {
215                 aBlock[4] = 0x01;
216                 break;
217             }
218             case A_FCNT_DOWN:
219             {
220                 aBlock[4] = 0x02;
221                 break;
222             }
223             default:
224                 return LORAMAC_CRYPTO_FAIL_PARAM;
225         }
226     }
227 
228     aBlock[5] = dir;
229 
230     aBlock[6] = address & 0xFF;
231     aBlock[7] = ( address >> 8 ) & 0xFF;
232     aBlock[8] = ( address >> 16 ) & 0xFF;
233     aBlock[9] = ( address >> 24 ) & 0xFF;
234 
235     aBlock[10] = frameCounter & 0xFF;
236     aBlock[11] = ( frameCounter >> 8 ) & 0xFF;
237     aBlock[12] = ( frameCounter >> 16 ) & 0xFF;
238     aBlock[13] = ( frameCounter >> 24 ) & 0xFF;
239 
240     if( CryptoNvm->LrWanVersion.Value > 0x01010000 )
241     {
242         // Introduced in LoRaWAN 1.1.1 specification
243         aBlock[15] = 0x01;
244     }
245 
246     if( size > 0 )
247     {
248         if( SecureElementAesEncrypt( aBlock, 16, NWK_S_ENC_KEY, sBlock ) != SECURE_ELEMENT_SUCCESS )
249         {
250             return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
251         }
252         for( uint8_t i = 0; i < size; i++ )
253         {
254             buffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
255         }
256     }
257 
258     return LORAMAC_CRYPTO_SUCCESS;
259 }
260 #endif
261 
262 /*
263  * Prepares B0 block for cmac computation.
264  *
265  * \param[IN]  msgLen         - Length of message
266  * \param[IN]  keyID          - Key identifier
267  * \param[IN]  isAck          - True if it is a acknowledge frame ( Sets ConfFCnt in B0 block )
268  * \param[IN]  devAddr        - Device address
269  * \param[IN]  dir            - Frame direction ( Uplink:0, Downlink:1 )
270  * \param[IN]  fCnt           - Frame counter
271  * \param[IN/OUT]  b0         - B0 block
272  * \retval                    - Status of the operation
273  */
PrepareB0(uint16_t msgLen,KeyIdentifier_t keyID,bool isAck,uint8_t dir,uint32_t devAddr,uint32_t fCnt,uint8_t * b0)274 static LoRaMacCryptoStatus_t PrepareB0( uint16_t msgLen, KeyIdentifier_t keyID, bool isAck, uint8_t dir, uint32_t devAddr, uint32_t fCnt, uint8_t* b0 )
275 {
276     if( b0 == 0 )
277     {
278         return LORAMAC_CRYPTO_ERROR_NPE;
279     }
280 
281     b0[0] = 0x49;
282 
283 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
284     if( ( isAck == true ) && ( dir == DOWNLINK ) )
285     {
286         // confFCnt contains the frame counter value modulo 2^16 of the "confirmed" uplink or downlink frame that is being acknowledged
287         uint16_t confFCnt = 0;
288 
289         confFCnt = ( uint16_t )( CryptoNvm->FCntList.FCntUp % 65536 );
290 
291         b0[1] = confFCnt & 0xFF;
292         b0[2] = ( confFCnt >> 8 ) & 0xFF;
293     }
294     else
295 #endif
296     {
297         b0[1] = 0x00;
298         b0[2] = 0x00;
299     }
300 
301     b0[3] = 0x00;
302     b0[4] = 0x00;
303 
304     b0[5] = dir;
305 
306     b0[6] = devAddr & 0xFF;
307     b0[7] = ( devAddr >> 8 ) & 0xFF;
308     b0[8] = ( devAddr >> 16 ) & 0xFF;
309     b0[9] = ( devAddr >> 24 ) & 0xFF;
310 
311     b0[10] = fCnt & 0xFF;
312     b0[11] = ( fCnt >> 8 ) & 0xFF;
313     b0[12] = ( fCnt >> 16 ) & 0xFF;
314     b0[13] = ( fCnt >> 24 ) & 0xFF;
315 
316     b0[14] = 0x00;
317 
318     b0[15] = msgLen & 0xFF;
319 
320     return LORAMAC_CRYPTO_SUCCESS;
321 }
322 
323 /*
324  * Computes cmac with adding B0 block in front.
325  *
326  *  cmac = aes128_cmac(keyID, B0 | msg)
327  *
328  * \param[IN]  msg            - Message to compute the integrity code
329  * \param[IN]  len            - Length of message
330  * \param[IN]  keyID          - Key identifier
331  * \param[IN]  isAck          - True if it is a acknowledge frame ( Sets ConfFCnt in B0 block )
332  * \param[IN]  devAddr        - Device address
333  * \param[IN]  dir            - Frame direction ( Uplink:0, Downlink:1 )
334  * \param[IN]  fCnt           - Frame counter
335  * \param[OUT] cmac           - Computed cmac
336  * \retval                    - Status of the operation
337  */
ComputeCmacB0(uint8_t * msg,uint16_t len,KeyIdentifier_t keyID,bool isAck,uint8_t dir,uint32_t devAddr,uint32_t fCnt,uint32_t * cmac)338 static LoRaMacCryptoStatus_t ComputeCmacB0( uint8_t* msg, uint16_t len, KeyIdentifier_t keyID, bool isAck, uint8_t dir, uint32_t devAddr, uint32_t fCnt, uint32_t* cmac )
339 {
340     if( ( msg == 0 ) || ( cmac == 0 ) )
341     {
342         return LORAMAC_CRYPTO_ERROR_NPE;
343     }
344     if( len > CRYPTO_MAXMESSAGE_SIZE )
345     {
346         return LORAMAC_CRYPTO_ERROR_BUF_SIZE;
347     }
348 
349     uint8_t micBuff[MIC_BLOCK_BX_SIZE];
350 
351     // Initialize the first Block
352     PrepareB0( len, keyID, isAck, dir, devAddr, fCnt, micBuff );
353 
354     if( SecureElementComputeAesCmac( micBuff, msg, len, keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
355     {
356         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
357     }
358     return LORAMAC_CRYPTO_SUCCESS;
359 }
360 
361 /*!
362  * Verifies cmac with adding B0 block in front.
363  *
364  * \param[IN]  msg            - Message to compute the integrity code
365  * \param[IN]  len            - Length of message
366  * \param[IN]  keyID          - Key identifier
367  * \param[IN]  isAck          - True if it is a acknowledge frame ( Sets ConfFCnt in B0 block )
368  * \param[IN]  devAddr        - Device address
369  * \param[IN]  dir            - Frame direction ( Uplink:0, Downlink:1 )
370  * \param[IN]  fCnt           - Frame counter
371  * \param[in]  expectedCmac   - Expected cmac
372  * \retval                    - Status of the operation
373  */
VerifyCmacB0(uint8_t * msg,uint16_t len,KeyIdentifier_t keyID,bool isAck,uint8_t dir,uint32_t devAddr,uint32_t fCnt,uint32_t expectedCmac)374 static LoRaMacCryptoStatus_t VerifyCmacB0( uint8_t* msg, uint16_t len, KeyIdentifier_t keyID, bool isAck, uint8_t dir, uint32_t devAddr, uint32_t fCnt, uint32_t expectedCmac )
375 {
376     if( msg == 0 )
377     {
378         return LORAMAC_CRYPTO_ERROR_NPE;
379     }
380     if( len > CRYPTO_MAXMESSAGE_SIZE )
381     {
382         return LORAMAC_CRYPTO_ERROR_BUF_SIZE;
383     }
384 
385     uint8_t micBuff[CRYPTO_BUFFER_SIZE];
386     memset1( micBuff, 0, CRYPTO_BUFFER_SIZE );
387 
388     // Initialize the first Block
389     PrepareB0( len, keyID, isAck, dir, devAddr, fCnt, micBuff );
390 
391     // Copy the given data to the mic computation buffer
392     memcpy1( ( micBuff + MIC_BLOCK_BX_SIZE ), msg, len );
393 
394     SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
395     retval = SecureElementVerifyAesCmac( micBuff, ( len + MIC_BLOCK_BX_SIZE ), expectedCmac, keyID );
396 
397     if( retval == SECURE_ELEMENT_SUCCESS )
398     {
399         return LORAMAC_CRYPTO_SUCCESS;
400     }
401     else if( retval == SECURE_ELEMENT_FAIL_CMAC )
402     {
403         return LORAMAC_CRYPTO_FAIL_MIC;
404     }
405 
406     return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
407 }
408 
409 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
410 /*
411  * Prpares B1 block for cmac computation.
412  *
413  * \param[IN]  msgLen         - Length of message
414  * \param[IN]  keyID          - Key identifier
415  * \param[IN]  isAck          - True if it is a acknowledge frame ( Sets ConfFCnt in B0 block )
416  * \param[IN]  txDr           - Data rate used for the transmission
417  * \param[IN]  txCh           - Index of the channel used for the transmission
418  * \param[IN]  devAddr        - Device address
419  * \param[IN]  fCntUp         - Frame counter
420  * \param[IN/OUT]  b0         - B0 block
421  * \retval                    - Status of the operation
422  */
PrepareB1(uint16_t msgLen,KeyIdentifier_t keyID,bool isAck,uint8_t txDr,uint8_t txCh,uint32_t devAddr,uint32_t fCntUp,uint8_t * b1)423 static LoRaMacCryptoStatus_t PrepareB1( uint16_t msgLen, KeyIdentifier_t keyID, bool isAck, uint8_t txDr, uint8_t txCh, uint32_t devAddr, uint32_t fCntUp, uint8_t* b1 )
424 {
425     if( b1 == 0 )
426     {
427         return LORAMAC_CRYPTO_ERROR_NPE;
428     }
429 
430     b1[0] = 0x49;
431 
432     if( isAck == true )
433     {
434         // confFCnt contains the frame counter value modulo 2^16 of the "confirmed" uplink frame that is being acknowledged
435         uint16_t confFCnt = ( uint16_t )( CryptoNvm->LastDownFCnt % 65536 );
436         b1[1] = confFCnt & 0xFF;
437         b1[2] = ( confFCnt >> 8 ) & 0xFF;
438     }
439     else
440     {
441         b1[1] = 0x00;
442         b1[2] = 0x00;
443     }
444 
445     b1[3] = txDr;
446     b1[4] = txCh;
447     b1[5] = UPLINK;  // dir = Uplink
448 
449     b1[6] = devAddr & 0xFF;
450     b1[7] = ( devAddr >> 8 ) & 0xFF;
451     b1[8] = ( devAddr >> 16 ) & 0xFF;
452     b1[9] = ( devAddr >> 24 ) & 0xFF;
453 
454     b1[10] = fCntUp & 0xFF;
455     b1[11] = ( fCntUp >> 8 ) & 0xFF;
456     b1[12] = ( fCntUp >> 16 ) & 0xFF;
457     b1[13] = ( fCntUp >> 24 ) & 0xFF;
458 
459     b1[14] = 0x00;
460 
461     b1[15] = msgLen & 0xFF;
462 
463     return LORAMAC_CRYPTO_SUCCESS;
464 }
465 
466 /*
467  * Computes cmac with adding B1 block in front ( only for Uplink frames LoRaWAN 1.1 )
468  *
469  *  cmac = aes128_cmac(keyID, B1 | msg)
470  *
471  * \param[IN]  msg            - Message to calculate the Integrity code
472  * \param[IN]  len            - Length of message
473  * \param[IN]  keyID          - Key identifier
474  * \param[IN]  isAck          - True if it is a acknowledge frame ( Sets ConfFCnt in B0 block )
475  * \param[IN]  txDr           - Data rate used for the transmission
476  * \param[IN]  txCh           - Index of the channel used for the transmission
477  * \param[IN]  devAddr        - Device address
478  * \param[IN]  fCntUp         - Uplink Frame counter
479  * \param[OUT] cmac           - Computed cmac
480  * \retval                    - Status of the operation
481  */
ComputeCmacB1(uint8_t * msg,uint16_t len,KeyIdentifier_t keyID,bool isAck,uint8_t txDr,uint8_t txCh,uint32_t devAddr,uint32_t fCntUp,uint32_t * cmac)482 static LoRaMacCryptoStatus_t ComputeCmacB1( uint8_t* msg, uint16_t len, KeyIdentifier_t keyID, bool isAck, uint8_t txDr, uint8_t txCh, uint32_t devAddr, uint32_t fCntUp, uint32_t* cmac )
483 {
484     if( ( msg == 0 ) || ( cmac == 0 ) )
485     {
486         return LORAMAC_CRYPTO_ERROR_NPE;
487     }
488     if( len > CRYPTO_MAXMESSAGE_SIZE )
489     {
490         return LORAMAC_CRYPTO_ERROR_BUF_SIZE;
491     }
492 
493     uint8_t micBuff[MIC_BLOCK_BX_SIZE];
494 
495     // Initialize the first Block
496     PrepareB1( len, keyID, isAck, txDr, txCh, devAddr, fCntUp, micBuff );
497 
498     if( SecureElementComputeAesCmac( micBuff, msg, len, keyID, cmac ) != SECURE_ELEMENT_SUCCESS )
499     {
500         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
501     }
502     return LORAMAC_CRYPTO_SUCCESS;
503 }
504 #endif
505 
506 /*
507  * Gets security item from list.
508  *
509  * \param[IN]  addrID          - Address identifier
510  * \param[OUT] keyItem        - Key item reference
511  * \retval                    - Status of the operation
512  */
GetKeyAddrItem(AddressIdentifier_t addrID,KeyAddr_t ** item)513 static LoRaMacCryptoStatus_t GetKeyAddrItem( AddressIdentifier_t addrID, KeyAddr_t** item )
514 {
515     for( uint8_t i = 0; i < NUM_OF_SEC_CTX; i++ )
516     {
517         if( KeyAddrList[i].AddrID == addrID )
518         {
519             *item = &( KeyAddrList[i] );
520             return LORAMAC_CRYPTO_SUCCESS;
521         }
522     }
523     return LORAMAC_CRYPTO_ERROR_INVALID_ADDR_ID;
524 }
525 
526 /*
527  * Derives a session key as of LoRaWAN versions prior to 1.1.0
528  *
529  * \param[IN]  keyID          - Key Identifier for the key to be calculated
530  * \param[IN]  joinNonce      - Sever nonce
531  * \param[IN]  netID          - Network Identifier
532  * \param[IN]  deviceNonce    - Device nonce
533  * \retval                    - Status of the operation
534  */
DeriveSessionKey10x(KeyIdentifier_t keyID,uint32_t joinNonce,uint32_t netID,uint16_t devNonce)535 static LoRaMacCryptoStatus_t DeriveSessionKey10x( KeyIdentifier_t keyID, uint32_t joinNonce, uint32_t netID, uint16_t devNonce )
536 {
537     uint8_t compBase[16] = { 0 };
538 
539     switch( keyID )
540     {
541         case F_NWK_S_INT_KEY:
542         case S_NWK_S_INT_KEY:
543         case NWK_S_ENC_KEY:
544             compBase[0] = 0x01;
545             break;
546         case APP_S_KEY:
547             compBase[0] = 0x02;
548             break;
549         default:
550             return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
551     }
552 
553     compBase[1] = ( uint8_t )( ( joinNonce >> 0 ) & 0xFF );
554     compBase[2] = ( uint8_t )( ( joinNonce >> 8 ) & 0xFF );
555     compBase[3] = ( uint8_t )( ( joinNonce >> 16 ) & 0xFF );
556 
557     compBase[4] = ( uint8_t )( ( netID >> 0 ) & 0xFF );
558     compBase[5] = ( uint8_t )( ( netID >> 8 ) & 0xFF );
559     compBase[6] = ( uint8_t )( ( netID >> 16 ) & 0xFF );
560 
561     compBase[7] = ( uint8_t )( ( devNonce >> 0 ) & 0xFF );
562     compBase[8] = ( uint8_t )( ( devNonce >> 8 ) & 0xFF );
563 
564     if( SecureElementDeriveAndStoreKey( compBase, NWK_KEY, keyID ) != SECURE_ELEMENT_SUCCESS )
565     {
566         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
567     }
568 
569     return LORAMAC_CRYPTO_SUCCESS;
570 }
571 
572 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
573 /*
574  * Derives a session key as of LoRaWAN 1.1.0
575  *
576  * \param[IN]  keyID          - Key Identifier for the key to be calculated
577  * \param[IN]  joinNonce      - Sever nonce
578  * \param[IN]  joinEUI        - Join Server EUI
579  * \param[IN]  deviceNonce    - Device nonce
580  * \retval                    - Status of the operation
581  */
DeriveSessionKey11x(KeyIdentifier_t keyID,uint32_t joinNonce,uint8_t * joinEUI,uint16_t devNonce)582 static LoRaMacCryptoStatus_t DeriveSessionKey11x( KeyIdentifier_t keyID, uint32_t joinNonce, uint8_t* joinEUI, uint16_t devNonce )
583 {
584     if( joinEUI == 0 )
585     {
586         return LORAMAC_CRYPTO_ERROR_NPE;
587     }
588 
589     uint8_t compBase[16] = { 0 };
590     KeyIdentifier_t rootKeyId = NWK_KEY;
591 
592     switch( keyID )
593     {
594         case F_NWK_S_INT_KEY:
595             compBase[0] = 0x01;
596             break;
597         case S_NWK_S_INT_KEY:
598             compBase[0] = 0x03;
599             break;
600         case NWK_S_ENC_KEY:
601             compBase[0] = 0x04;
602             break;
603         case APP_S_KEY:
604             rootKeyId = APP_KEY;
605             compBase[0] = 0x02;
606             break;
607         default:
608             return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
609     }
610 
611     compBase[1] = ( uint8_t )( ( joinNonce >> 0 ) & 0xFF );
612     compBase[2] = ( uint8_t )( ( joinNonce >> 8 ) & 0xFF );
613     compBase[3] = ( uint8_t )( ( joinNonce >> 16 ) & 0xFF );
614 
615     memcpyr( compBase + 4, joinEUI, 8 );
616 
617     compBase[12] = ( uint8_t )( ( devNonce >> 0 ) & 0xFF );
618     compBase[13] = ( uint8_t )( ( devNonce >> 8 ) & 0xFF );
619 
620     if( SecureElementDeriveAndStoreKey( compBase, rootKeyId, keyID ) != SECURE_ELEMENT_SUCCESS )
621     {
622         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
623     }
624 
625     return LORAMAC_CRYPTO_SUCCESS;
626 }
627 
628 /*
629  * Derives a life time session key (JSIntKey or JSEncKey)  as of LoRaWAN 1.1.0
630  *
631  * \param[IN]  keyID          - Key Identifier for the key to be calculated
632  * \param[IN]  devEUI         - Device EUI
633  * \retval                    - Status of the operation
634  */
DeriveLifeTimeSessionKey(KeyIdentifier_t keyID,uint8_t * devEUI)635 static LoRaMacCryptoStatus_t DeriveLifeTimeSessionKey( KeyIdentifier_t keyID, uint8_t* devEUI )
636 {
637     if( devEUI == 0 )
638     {
639         return LORAMAC_CRYPTO_ERROR_NPE;
640     }
641 
642     uint8_t compBase[16] = { 0 };
643 
644     switch( keyID )
645     {
646         case J_S_INT_KEY:
647             compBase[0] = 0x06;
648             break;
649         case J_S_ENC_KEY:
650             compBase[0] = 0x05;
651             break;
652         default:
653             return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
654     }
655 
656     memcpyr( compBase + 1, devEUI, 8 );
657 
658     if( SecureElementDeriveAndStoreKey( compBase, NWK_KEY, keyID ) != SECURE_ELEMENT_SUCCESS )
659     {
660         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
661     }
662 
663     return LORAMAC_CRYPTO_SUCCESS;
664 }
665 #endif
666 
667 /*
668  * Gets the last received frame counter
669  *
670  * \param[IN]     fCntID       - Frame counter identifier
671  * \param[IN]     lastDown     - Last downlink counter value
672  *
673  * \retval                     - Status of the operation
674  */
GetLastFcntDown(FCntIdentifier_t fCntID,uint32_t * lastDown)675 static LoRaMacCryptoStatus_t GetLastFcntDown( FCntIdentifier_t fCntID, uint32_t* lastDown )
676 {
677     if( lastDown == NULL )
678     {
679         return LORAMAC_CRYPTO_ERROR_NPE;
680     }
681     switch( fCntID )
682     {
683         case N_FCNT_DOWN:
684             *lastDown = CryptoNvm->FCntList.NFCntDown;
685             CryptoNvm->LastDownFCnt = CryptoNvm->FCntList.NFCntDown;
686             break;
687         case A_FCNT_DOWN:
688             *lastDown = CryptoNvm->FCntList.AFCntDown;
689             CryptoNvm->LastDownFCnt = CryptoNvm->FCntList.AFCntDown;
690             break;
691         case FCNT_DOWN:
692             *lastDown = CryptoNvm->FCntList.FCntDown;
693             CryptoNvm->LastDownFCnt = CryptoNvm->FCntList.FCntDown;
694             break;
695 #if ( LORAMAC_MAX_MC_CTX > 0 )
696         case MC_FCNT_DOWN_0:
697             *lastDown = CryptoNvm->FCntList.McFCntDown[0];
698             break;
699 #endif
700 #if ( LORAMAC_MAX_MC_CTX > 1 )
701         case MC_FCNT_DOWN_1:
702             *lastDown = CryptoNvm->FCntList.McFCntDown[1];
703             break;
704 #endif
705 #if ( LORAMAC_MAX_MC_CTX > 2 )
706         case MC_FCNT_DOWN_2:
707             *lastDown = CryptoNvm->FCntList.McFCntDown[2];
708             break;
709 #endif
710 #if ( LORAMAC_MAX_MC_CTX > 3 )
711         case MC_FCNT_DOWN_3:
712             *lastDown = CryptoNvm->FCntList.McFCntDown[3];
713             break;
714 #endif
715         default:
716             return LORAMAC_CRYPTO_FAIL_FCNT_ID;
717     }
718     return LORAMAC_CRYPTO_SUCCESS;
719 }
720 
721 /*
722  * Checks the downlink counter value
723  *
724  * \param[IN]     fCntID       - Frame counter identifier
725  * \param[IN]     currentDown  - Current downlink counter value
726  *
727  * \retval                     - Status of the operation
728  */
CheckFCntDown(FCntIdentifier_t fCntID,uint32_t currentDown)729 static bool CheckFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
730 {
731     uint32_t lastDown = 0;
732     if( GetLastFcntDown( fCntID, &lastDown ) != LORAMAC_CRYPTO_SUCCESS )
733     {
734         return false;
735     }
736     if( ( currentDown > lastDown ) ||
737         // For LoRaWAN 1.0.X only. Allow downlink frames of 0
738         ( lastDown == FCNT_DOWN_INITAL_VALUE ) )
739     {
740         return true;
741     }
742     else
743     {
744         return false;
745     }
746 }
747 
748 /*!
749  * Updates the reference downlink counter
750  *
751  * \param[IN]     fCntID        - Frame counter identifier
752  * \param[IN]     currentDown   - Current downlink counter value
753  *
754  * \retval                     - Status of the operation
755  */
UpdateFCntDown(FCntIdentifier_t fCntID,uint32_t currentDown)756 static void UpdateFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
757 {
758     switch( fCntID )
759     {
760         case N_FCNT_DOWN:
761             CryptoNvm->FCntList.NFCntDown = currentDown;
762             break;
763         case A_FCNT_DOWN:
764             CryptoNvm->FCntList.AFCntDown = currentDown;
765             break;
766         case FCNT_DOWN:
767             CryptoNvm->FCntList.FCntDown = currentDown;
768             break;
769 #if ( LORAMAC_MAX_MC_CTX > 0 )
770         case MC_FCNT_DOWN_0:
771             CryptoNvm->FCntList.McFCntDown[0] = currentDown;
772             break;
773 #endif
774 #if ( LORAMAC_MAX_MC_CTX > 1 )
775         case MC_FCNT_DOWN_1:
776             CryptoNvm->FCntList.McFCntDown[1] = currentDown;
777             break;
778 #endif
779 #if ( LORAMAC_MAX_MC_CTX > 2 )
780         case MC_FCNT_DOWN_2:
781             CryptoNvm->FCntList.McFCntDown[2] = currentDown;
782             break;
783 #endif
784 #if ( LORAMAC_MAX_MC_CTX > 3 )
785         case MC_FCNT_DOWN_3:
786             CryptoNvm->FCntList.McFCntDown[3] = currentDown;
787             break;
788 #endif
789         default:
790             break;
791     }
792 }
793 
794 /*!
795  * Resets the frame counters
796  */
ResetFCnts(void)797 static void ResetFCnts( void )
798 {
799     CryptoNvm->FCntList.FCntUp = 0;
800     CryptoNvm->FCntList.NFCntDown = FCNT_DOWN_INITAL_VALUE;
801     CryptoNvm->FCntList.AFCntDown = FCNT_DOWN_INITAL_VALUE;
802     CryptoNvm->FCntList.FCntDown = FCNT_DOWN_INITAL_VALUE;
803     CryptoNvm->LastDownFCnt = CryptoNvm->FCntList.FCntDown;
804 
805     for( int32_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
806     {
807         CryptoNvm->FCntList.McFCntDown[i] = FCNT_DOWN_INITAL_VALUE;
808     }
809 }
810 
IsJoinNonce10xOk(uint32_t joinNonce)811 static bool IsJoinNonce10xOk( uint32_t joinNonce )
812 {
813 #if( USE_10X_JOIN_NONCE_COUNTER_CHECK == 1 )
814     // Check if the JoinNonce is greater as the previous one
815     return ( joinNonce > CryptoNvm->JoinNonce ) ? true : false;
816 #else
817     // Check if the JoinNonce is different from the previous one
818     return( joinNonce != CryptoNvm->JoinNonce ) ? true : false;
819 #endif
820 }
821 
822 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
IsJoinNonce11xOk(uint32_t joinNonce)823 static bool IsJoinNonce11xOk( uint32_t joinNonce )
824 {
825     return ( joinNonce > CryptoNvm->JoinNonce ) ? true : false;
826 }
827 #endif
828 
829 /*
830  *  API functions
831  */
LoRaMacCryptoInit(LoRaMacCryptoNvmData_t * nvm)832 LoRaMacCryptoStatus_t LoRaMacCryptoInit( LoRaMacCryptoNvmData_t* nvm )
833 {
834     if( nvm == NULL )
835     {
836         return LORAMAC_CRYPTO_FAIL_PARAM;
837     }
838 
839     // Assign non volatile context
840     CryptoNvm = nvm;
841 
842     // Initialize with default
843     memset1( ( uint8_t* )CryptoNvm, 0, sizeof( LoRaMacCryptoNvmData_t ) );
844 
845     // Set default LoRaWAN version
846     CryptoNvm->LrWanVersion.Fields.Major = 1;
847     CryptoNvm->LrWanVersion.Fields.Minor = 1;
848     CryptoNvm->LrWanVersion.Fields.Patch = 1;
849     CryptoNvm->LrWanVersion.Fields.Revision = 0;
850 
851     // Reset frame counters
852     ResetFCnts( );
853 
854     return LORAMAC_CRYPTO_SUCCESS;
855 }
856 
LoRaMacCryptoSetLrWanVersion(Version_t version)857 LoRaMacCryptoStatus_t LoRaMacCryptoSetLrWanVersion( Version_t version )
858 {
859     CryptoNvm->LrWanVersion = version;
860     return LORAMAC_CRYPTO_SUCCESS;
861 }
862 
LoRaMacCryptoGetFCntUp(uint32_t * currentUp)863 LoRaMacCryptoStatus_t LoRaMacCryptoGetFCntUp( uint32_t* currentUp )
864 {
865     if( currentUp == NULL )
866     {
867         return LORAMAC_CRYPTO_ERROR_NPE;
868     }
869 
870     *currentUp = CryptoNvm->FCntList.FCntUp + 1;
871 
872     return LORAMAC_CRYPTO_SUCCESS;
873 }
874 
LoRaMacCryptoGetFCntDown(FCntIdentifier_t fCntID,uint32_t frameFcnt,uint32_t * currentDown)875 LoRaMacCryptoStatus_t LoRaMacCryptoGetFCntDown( FCntIdentifier_t fCntID, uint32_t frameFcnt, uint32_t* currentDown )
876 {
877     uint32_t lastDown = 0;
878     int32_t fCntDiff = 0;
879     LoRaMacCryptoStatus_t cryptoStatus = LORAMAC_CRYPTO_ERROR;
880 
881     if( currentDown == NULL )
882     {
883         return LORAMAC_CRYPTO_ERROR_NPE;
884     }
885 
886     cryptoStatus = GetLastFcntDown( fCntID, &lastDown );
887     if( cryptoStatus != LORAMAC_CRYPTO_SUCCESS )
888     {
889         return cryptoStatus;
890     }
891 
892     // For LoRaWAN 1.0.X only, allow downlink frames of 0
893     if( lastDown == FCNT_DOWN_INITAL_VALUE )
894     {
895         *currentDown = frameFcnt;
896     }
897     else
898     {
899         // Add difference, consider roll-over
900         fCntDiff = ( int32_t )( ( int64_t )frameFcnt - ( int64_t )( lastDown & 0x0000FFFF ) );
901 
902         if( fCntDiff > 0 )
903         {  // Positive difference
904             *currentDown = lastDown + fCntDiff;
905         }
906         else if( fCntDiff == 0 )
907         {  // Duplicate FCnt value, keep the current value.
908             *currentDown = lastDown;
909             return LORAMAC_CRYPTO_FAIL_FCNT_DUPLICATED;
910         }
911         else
912         {  // Negative difference, assume a roll-over of one uint16_t
913             *currentDown = ( lastDown & 0xFFFF0000 ) + 0x10000 + frameFcnt;
914         }
915     }
916 
917     return LORAMAC_CRYPTO_SUCCESS;
918 }
919 
LoRaMacCryptoGetRJcount(FCntIdentifier_t fCntID,uint16_t * rJcount)920 LoRaMacCryptoStatus_t LoRaMacCryptoGetRJcount( FCntIdentifier_t fCntID, uint16_t* rJcount )
921 {
922 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
923     if( rJcount == 0 )
924     {
925         return LORAMAC_CRYPTO_ERROR_NPE;
926     }
927     switch( fCntID )
928     {
929         case RJ_COUNT_0:
930             *rJcount = RJcount0 + 1;
931             break;
932         case RJ_COUNT_1:
933             *rJcount = CryptoNvm->FCntList.RJcount1 + 1;
934             break;
935         default:
936             return LORAMAC_CRYPTO_FAIL_FCNT_ID;
937     }
938     return LORAMAC_CRYPTO_SUCCESS;
939 #else
940     return LORAMAC_CRYPTO_ERROR;
941 #endif
942 }
943 
LoRaMacCryptoSetMulticastReference(MulticastCtx_t * multicastList)944 LoRaMacCryptoStatus_t LoRaMacCryptoSetMulticastReference( MulticastCtx_t* multicastList )
945 {
946     if( multicastList == NULL )
947     {
948         return LORAMAC_CRYPTO_ERROR_NPE;
949     }
950 
951     for( int32_t i = 0; i < LORAMAC_MAX_MC_CTX; i++ )
952     {
953         multicastList[i].DownLinkCounter = &CryptoNvm->FCntList.McFCntDown[i];
954     }
955 
956     return LORAMAC_CRYPTO_SUCCESS;
957 }
958 
LoRaMacCryptoSetKey(KeyIdentifier_t keyID,uint8_t * key)959 LoRaMacCryptoStatus_t LoRaMacCryptoSetKey( KeyIdentifier_t keyID, uint8_t* key )
960 {
961     if( SecureElementSetKey( keyID, key ) != SECURE_ELEMENT_SUCCESS )
962     {
963         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
964     }
965     if( keyID == APP_KEY )
966     {
967         // Derive lifetime keys
968         if( LoRaMacCryptoDeriveMcRootKey( CryptoNvm->LrWanVersion.Fields.Minor, keyID ) != LORAMAC_CRYPTO_SUCCESS )
969         {
970             return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
971         }
972         if( LoRaMacCryptoDeriveMcKEKey( MC_ROOT_KEY ) != LORAMAC_CRYPTO_SUCCESS )
973         {
974             return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
975         }
976     }
977     return LORAMAC_CRYPTO_SUCCESS;
978 }
979 
LoRaMacCryptoPrepareJoinRequest(LoRaMacMessageJoinRequest_t * macMsg)980 LoRaMacCryptoStatus_t LoRaMacCryptoPrepareJoinRequest( LoRaMacMessageJoinRequest_t* macMsg )
981 {
982     if( macMsg == 0 )
983     {
984         return LORAMAC_CRYPTO_ERROR_NPE;
985     }
986     KeyIdentifier_t micComputationKeyID = NWK_KEY;
987 
988     // Add device nonce
989 #if ( USE_RANDOM_DEV_NONCE == 1 )
990     uint32_t devNonce = 0;
991     SecureElementRandomNumber( &devNonce );
992     CryptoNvm->DevNonce = devNonce;
993 #else
994     CryptoNvm->DevNonce++;
995 #endif
996     macMsg->DevNonce = CryptoNvm->DevNonce;
997 
998 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
999     // Derive lifetime session keys
1000     if( DeriveLifeTimeSessionKey( J_S_INT_KEY, macMsg->DevEUI ) != LORAMAC_CRYPTO_SUCCESS )
1001     {
1002         return LORAMAC_CRYPTO_ERROR;
1003     }
1004     if( DeriveLifeTimeSessionKey( J_S_ENC_KEY, macMsg->DevEUI ) != LORAMAC_CRYPTO_SUCCESS )
1005     {
1006         return LORAMAC_CRYPTO_ERROR;
1007     }
1008 #endif
1009 
1010     // Serialize message
1011     if( LoRaMacSerializerJoinRequest( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1012     {
1013         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1014     }
1015 
1016     // Compute mic
1017     if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_JOIN_REQ_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
1018     {
1019         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1020     }
1021 
1022     // Reserialize message to add the MIC
1023     if( LoRaMacSerializerJoinRequest( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1024     {
1025         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1026     }
1027 
1028     return LORAMAC_CRYPTO_SUCCESS;
1029 }
1030 
LoRaMacCryptoPrepareReJoinType1(LoRaMacMessageReJoinType1_t * macMsg)1031 LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType1( LoRaMacMessageReJoinType1_t* macMsg )
1032 {
1033 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1034     if( macMsg == 0 )
1035     {
1036         return LORAMAC_CRYPTO_ERROR_NPE;
1037     }
1038 
1039     // Check for RJcount1 overflow
1040     if( CryptoNvm->FCntList.RJcount1 == 65535 )
1041     {
1042         return LORAMAC_CRYPTO_ERROR_RJCOUNT1_OVERFLOW;
1043     }
1044 
1045     // Serialize message
1046     if( LoRaMacSerializerReJoinType1( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1047     {
1048         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1049     }
1050 
1051     // Compute mic
1052     // cmac = aes128_cmac(JSIntKey, MHDR | RejoinType | JoinEUI| DevEUI | RJcount1)
1053     if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_RE_JOIN_1_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), J_S_INT_KEY, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
1054     {
1055         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1056     }
1057 
1058     // Reserialize message to add the MIC
1059     if( LoRaMacSerializerReJoinType1( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1060     {
1061         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1062     }
1063 
1064     // Increment RJcount1
1065     CryptoNvm->FCntList.RJcount1++;
1066 
1067     return LORAMAC_CRYPTO_SUCCESS;
1068 #else
1069     return LORAMAC_CRYPTO_ERROR;
1070 #endif
1071 }
1072 
LoRaMacCryptoPrepareReJoinType0or2(LoRaMacMessageReJoinType0or2_t * macMsg)1073 LoRaMacCryptoStatus_t LoRaMacCryptoPrepareReJoinType0or2( LoRaMacMessageReJoinType0or2_t* macMsg )
1074 {
1075 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1076     if( macMsg == 0 )
1077     {
1078         return LORAMAC_CRYPTO_ERROR_NPE;
1079     }
1080 
1081     // Check for RJcount0 overflow
1082     if( RJcount0 == 65535 )
1083     {
1084         return LORAMAC_CRYPTO_FAIL_RJCOUNT0_OVERFLOW;
1085     }
1086 
1087     // Serialize message
1088     if( LoRaMacSerializerReJoinType0or2( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1089     {
1090         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1091     }
1092 
1093     // Compute mic
1094     // cmac = aes128_cmac(SNwkSIntKey, MHDR | Rejoin Type | NetID | DevEUI | RJcount0)
1095     if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_RE_JOIN_0_2_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), S_NWK_S_INT_KEY, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
1096     {
1097         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1098     }
1099 
1100     // Re-serialize message to add the MIC
1101     if( LoRaMacSerializerReJoinType0or2( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1102     {
1103         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1104     }
1105 
1106     // Increment RJcount0
1107     RJcount0++;
1108 
1109     return LORAMAC_CRYPTO_SUCCESS;
1110 #else
1111     return LORAMAC_CRYPTO_ERROR;
1112 #endif
1113 }
1114 
LoRaMacCryptoHandleJoinAccept(JoinReqIdentifier_t joinReqType,uint8_t * joinEUI,LoRaMacMessageJoinAccept_t * macMsg)1115 LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEUI, LoRaMacMessageJoinAccept_t* macMsg )
1116 {
1117     if( ( macMsg == 0 ) || ( joinEUI == 0 ) )
1118     {
1119         return LORAMAC_CRYPTO_ERROR_NPE;
1120     }
1121 
1122     LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
1123     uint8_t decJoinAccept[LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE] = { 0 };
1124     uint8_t versionMinor         = 0;
1125     uint16_t nonce               = CryptoNvm->DevNonce;
1126 
1127     // Nonce selection depending on JoinReqType
1128     // JOIN_REQ     : CryptoNvm->DevNonce
1129     // REJOIN_REQ_0 : RJcount0
1130     // REJOIN_REQ_1 : CryptoCtx.RJcount1
1131     // REJOIN_REQ_2 : RJcount0
1132     if( joinReqType == JOIN_REQ )
1133     {
1134         // Nothing to be done
1135     }
1136 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1137     else
1138     {
1139         // If Join-accept is a reply to a rejoin, the RJcount(0 or 1) replaces DevNonce in the key derivation process.
1140         if( ( joinReqType == REJOIN_REQ_0 ) || ( joinReqType == REJOIN_REQ_2 ) )
1141         {
1142             nonce = RJcount0;
1143         }
1144         else
1145         {
1146             nonce = CryptoNvm->FCntList.RJcount1;
1147         }
1148     }
1149 #endif
1150 
1151     if( SecureElementProcessJoinAccept( joinReqType, joinEUI, nonce, macMsg->Buffer,
1152                                         macMsg->BufSize, decJoinAccept,
1153                                         &versionMinor ) != SECURE_ELEMENT_SUCCESS )
1154     {
1155         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1156     }
1157 
1158     memcpy1( macMsg->Buffer, decJoinAccept, macMsg->BufSize );
1159 
1160     // Parse the message
1161     if( LoRaMacParserJoinAccept( macMsg ) != LORAMAC_PARSER_SUCCESS )
1162     {
1163         return LORAMAC_CRYPTO_ERROR_PARSER;
1164     }
1165 
1166     uint32_t currentJoinNonce;
1167     bool isJoinNonceOk = false;
1168 
1169     currentJoinNonce = ( uint32_t )macMsg->JoinNonce[0];
1170     currentJoinNonce |= ( ( uint32_t )macMsg->JoinNonce[1] << 8 );
1171     currentJoinNonce |= ( ( uint32_t )macMsg->JoinNonce[2] << 16 );
1172 
1173 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1174     if( versionMinor == 1 )
1175     {
1176         isJoinNonceOk = IsJoinNonce11xOk( currentJoinNonce );
1177     }
1178     else
1179 #endif
1180     {
1181         isJoinNonceOk = IsJoinNonce10xOk( currentJoinNonce );
1182     }
1183 
1184     if( isJoinNonceOk == true )
1185     {
1186         CryptoNvm->JoinNonce = currentJoinNonce;
1187     }
1188     else
1189     {
1190         return LORAMAC_CRYPTO_FAIL_JOIN_NONCE;
1191     }
1192 
1193     // Derive lifetime keys
1194     retval = LoRaMacCryptoDeriveMcRootKey( versionMinor, APP_KEY );
1195     if( retval != LORAMAC_CRYPTO_SUCCESS )
1196     {
1197         return retval;
1198     }
1199 
1200     retval = LoRaMacCryptoDeriveMcKEKey( MC_ROOT_KEY );
1201     if( retval != LORAMAC_CRYPTO_SUCCESS )
1202     {
1203         return retval;
1204     }
1205 
1206 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1207     if( versionMinor == 1 )
1208     {
1209         // Operating in LoRaWAN 1.1.x mode
1210 
1211         retval = DeriveSessionKey11x( F_NWK_S_INT_KEY, currentJoinNonce, joinEUI, nonce );
1212         if( retval != LORAMAC_CRYPTO_SUCCESS )
1213         {
1214             return retval;
1215         }
1216 
1217         retval = DeriveSessionKey11x( S_NWK_S_INT_KEY, currentJoinNonce, joinEUI, nonce );
1218         if( retval != LORAMAC_CRYPTO_SUCCESS )
1219         {
1220             return retval;
1221         }
1222 
1223         retval = DeriveSessionKey11x( NWK_S_ENC_KEY, currentJoinNonce, joinEUI, nonce );
1224         if( retval != LORAMAC_CRYPTO_SUCCESS )
1225         {
1226             return retval;
1227         }
1228 
1229         retval = DeriveSessionKey11x( APP_S_KEY, currentJoinNonce, joinEUI, nonce );
1230         if( retval != LORAMAC_CRYPTO_SUCCESS )
1231         {
1232             return retval;
1233         }
1234     }
1235     else
1236 #endif
1237     {
1238         // Operating in LoRaWAN 1.0.x mode
1239 
1240         uint32_t netID;
1241 
1242         netID = ( uint32_t )macMsg->NetID[0];
1243         netID |= ( ( uint32_t )macMsg->NetID[1] << 8 );
1244         netID |= ( ( uint32_t )macMsg->NetID[2] << 16 );
1245 
1246         retval = DeriveSessionKey10x( APP_S_KEY, currentJoinNonce, netID, nonce );
1247         if( retval != LORAMAC_CRYPTO_SUCCESS )
1248         {
1249             return retval;
1250         }
1251 
1252         retval = DeriveSessionKey10x( NWK_S_ENC_KEY, currentJoinNonce, netID, nonce );
1253         if( retval != LORAMAC_CRYPTO_SUCCESS )
1254         {
1255             return retval;
1256         }
1257 
1258         retval = DeriveSessionKey10x( F_NWK_S_INT_KEY, currentJoinNonce, netID, nonce );
1259         if( retval != LORAMAC_CRYPTO_SUCCESS )
1260         {
1261             return retval;
1262         }
1263 
1264         retval = DeriveSessionKey10x( S_NWK_S_INT_KEY, currentJoinNonce, netID, nonce );
1265         if( retval != LORAMAC_CRYPTO_SUCCESS )
1266         {
1267             return retval;
1268         }
1269     }
1270 
1271     // Join-Accept is successfully processed
1272     // Save LoRaWAN specification version
1273     CryptoNvm->LrWanVersion.Fields.Minor = versionMinor;
1274 
1275     // Reset frame counters
1276 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1277     RJcount0 = 0;
1278 #endif
1279     CryptoNvm->FCntList.FCntUp = 0;
1280     CryptoNvm->FCntList.FCntDown = FCNT_DOWN_INITAL_VALUE;
1281     CryptoNvm->FCntList.NFCntDown = FCNT_DOWN_INITAL_VALUE;
1282     CryptoNvm->FCntList.AFCntDown = FCNT_DOWN_INITAL_VALUE;
1283 
1284     return LORAMAC_CRYPTO_SUCCESS;
1285 }
1286 
LoRaMacCryptoSecureMessage(uint32_t fCntUp,uint8_t txDr,uint8_t txCh,LoRaMacMessageData_t * macMsg)1287 LoRaMacCryptoStatus_t LoRaMacCryptoSecureMessage( uint32_t fCntUp, uint8_t txDr, uint8_t txCh, LoRaMacMessageData_t* macMsg )
1288 {
1289     LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
1290     KeyIdentifier_t payloadDecryptionKeyID = APP_S_KEY;
1291 
1292     if( macMsg == NULL )
1293     {
1294         return LORAMAC_CRYPTO_ERROR_NPE;
1295     }
1296 
1297     if( fCntUp < CryptoNvm->FCntList.FCntUp )
1298     {
1299         return LORAMAC_CRYPTO_FAIL_FCNT_SMALLER;
1300     }
1301 
1302     // Encrypt payload
1303     if( macMsg->FPort == 0 )
1304     {
1305         // Use network session key
1306         payloadDecryptionKeyID = NWK_S_ENC_KEY;
1307     }
1308 
1309     if( fCntUp > CryptoNvm->FCntList.FCntUp )
1310     {
1311         retval = PayloadEncrypt( macMsg->FRMPayload, macMsg->FRMPayloadSize, payloadDecryptionKeyID, macMsg->FHDR.DevAddr, UPLINK, fCntUp );
1312         if( retval != LORAMAC_CRYPTO_SUCCESS )
1313         {
1314             return retval;
1315         }
1316 
1317 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1318         if( CryptoNvm->LrWanVersion.Fields.Minor == 1 )
1319         {
1320             // Encrypt FOpts
1321             retval = FOptsEncrypt( macMsg->FHDR.FCtrl.Bits.FOptsLen, macMsg->FHDR.DevAddr, UPLINK, FCNT_UP, fCntUp, macMsg->FHDR.FOpts );
1322             if( retval != LORAMAC_CRYPTO_SUCCESS )
1323             {
1324                 return retval;
1325             }
1326         }
1327 #endif
1328     }
1329 
1330     // Serialize message
1331     if( LoRaMacSerializerData( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1332     {
1333         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1334     }
1335 
1336     // Compute mic
1337 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1338     if( CryptoNvm->LrWanVersion.Fields.Minor == 1 )
1339     {
1340         uint32_t cmacS = 0;
1341         uint32_t cmacF = 0;
1342 
1343         // cmacS  = aes128_cmac(SNwkSIntKey, B1 | msg)
1344         retval = ComputeCmacB1( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), S_NWK_S_INT_KEY, macMsg->FHDR.FCtrl.Bits.Ack, txDr, txCh, macMsg->FHDR.DevAddr, fCntUp, &cmacS );
1345         if( retval != LORAMAC_CRYPTO_SUCCESS )
1346         {
1347             return retval;
1348         }
1349         //cmacF = aes128_cmac(FNwkSIntKey, B0 | msg)
1350         retval = ComputeCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), F_NWK_S_INT_KEY, macMsg->FHDR.FCtrl.Bits.Ack, UPLINK, macMsg->FHDR.DevAddr, fCntUp, &cmacF );
1351         if( retval != LORAMAC_CRYPTO_SUCCESS )
1352         {
1353             return retval;
1354         }
1355         // MIC = cmacS[0..1] | cmacF[0..1]
1356         macMsg->MIC = ( ( cmacF << 16 ) & 0xFFFF0000 ) | ( cmacS & 0x0000FFFF );
1357     }
1358     else
1359 #endif
1360     {
1361         // MIC = cmacF[0..3]
1362         // The IsAck parameter is every time false since the ConfFCnt field is not used in legacy mode.
1363         retval = ComputeCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), NWK_S_ENC_KEY, false, UPLINK, macMsg->FHDR.DevAddr, fCntUp, &macMsg->MIC );
1364         if( retval != LORAMAC_CRYPTO_SUCCESS )
1365         {
1366             return retval;
1367         }
1368     }
1369 
1370     // Re-serialize message to add the MIC
1371     if( LoRaMacSerializerData( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
1372     {
1373         return LORAMAC_CRYPTO_ERROR_SERIALIZER;
1374     }
1375 
1376     CryptoNvm->FCntList.FCntUp = fCntUp;
1377 
1378     return LORAMAC_CRYPTO_SUCCESS;
1379 }
1380 
LoRaMacCryptoUnsecureMessage(AddressIdentifier_t addrID,uint32_t address,FCntIdentifier_t fCntID,uint32_t fCntDown,LoRaMacMessageData_t * macMsg)1381 LoRaMacCryptoStatus_t LoRaMacCryptoUnsecureMessage( AddressIdentifier_t addrID, uint32_t address, FCntIdentifier_t fCntID, uint32_t fCntDown, LoRaMacMessageData_t* macMsg )
1382 {
1383     if( macMsg == 0 )
1384     {
1385         return LORAMAC_CRYPTO_ERROR_NPE;
1386     }
1387 
1388     if( CheckFCntDown( fCntID, fCntDown ) == false )
1389     {
1390         return LORAMAC_CRYPTO_FAIL_FCNT_SMALLER;
1391     }
1392 
1393     LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
1394     KeyIdentifier_t payloadDecryptionKeyID = APP_S_KEY;
1395     KeyIdentifier_t micComputationKeyID = S_NWK_S_INT_KEY;
1396     KeyAddr_t* curItem;
1397 
1398     // Parse the message
1399     if( LoRaMacParserData( macMsg ) != LORAMAC_PARSER_SUCCESS )
1400     {
1401         return LORAMAC_CRYPTO_ERROR_PARSER;
1402     }
1403 
1404     // Determine current security context
1405     retval = GetKeyAddrItem( addrID, &curItem );
1406     if( retval != LORAMAC_CRYPTO_SUCCESS )
1407     {
1408         return retval;
1409     }
1410 
1411     payloadDecryptionKeyID = curItem->AppSkey;
1412     micComputationKeyID = curItem->NwkSkey;
1413 
1414     // Check if it is our address
1415     if( address != macMsg->FHDR.DevAddr )
1416     {
1417         return LORAMAC_CRYPTO_FAIL_ADDRESS;
1418     }
1419 
1420     // Compute mic
1421     bool isAck = macMsg->FHDR.FCtrl.Bits.Ack;
1422     if( CryptoNvm->LrWanVersion.Fields.Minor == 0 )
1423     {
1424         // In legacy mode the IsAck parameter is forced to be false since the ConfFCnt field is not used.
1425         isAck = false;
1426     }
1427 
1428     // Verify mic
1429     retval = VerifyCmacB0( macMsg->Buffer, ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, isAck, DOWNLINK, address, fCntDown, macMsg->MIC );
1430     if( retval != LORAMAC_CRYPTO_SUCCESS )
1431     {
1432         return retval;
1433     }
1434 
1435     // Decrypt payload
1436     if( macMsg->FPort == 0 )
1437     {
1438         // Use network session encryption key
1439         payloadDecryptionKeyID = NWK_S_ENC_KEY;
1440     }
1441     retval = PayloadEncrypt( macMsg->FRMPayload, macMsg->FRMPayloadSize, payloadDecryptionKeyID, address, DOWNLINK, fCntDown );
1442     if( retval != LORAMAC_CRYPTO_SUCCESS )
1443     {
1444         return retval;
1445     }
1446 
1447 #if( USE_LRWAN_1_1_X_CRYPTO == 1 )
1448     if( CryptoNvm->LrWanVersion.Fields.Minor == 1 )
1449     {
1450         if( addrID == UNICAST_DEV_ADDR )
1451         {
1452             // Decrypt FOpts
1453             retval = FOptsEncrypt( macMsg->FHDR.FCtrl.Bits.FOptsLen, address, DOWNLINK, fCntID, fCntDown, macMsg->FHDR.FOpts );
1454             if( retval != LORAMAC_CRYPTO_SUCCESS )
1455             {
1456                 return retval;
1457             }
1458         }
1459     }
1460 #endif
1461 
1462     UpdateFCntDown( fCntID, fCntDown );
1463 
1464     return LORAMAC_CRYPTO_SUCCESS;
1465 }
1466 
LoRaMacCryptoDeriveMcRootKey(uint8_t versionMinor,KeyIdentifier_t keyID)1467 LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcRootKey( uint8_t versionMinor, KeyIdentifier_t keyID )
1468 {
1469     // Prevent other keys than AppKey
1470     if( keyID != APP_KEY )
1471     {
1472         return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
1473     }
1474     uint8_t compBase[16] = { 0 };
1475 
1476     if( versionMinor == 1 )
1477     {
1478         compBase[0] = 0x20;
1479     }
1480     if( SecureElementDeriveAndStoreKey( compBase, keyID, MC_ROOT_KEY ) != SECURE_ELEMENT_SUCCESS )
1481     {
1482         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1483     }
1484 
1485     return LORAMAC_CRYPTO_SUCCESS;
1486 }
1487 
LoRaMacCryptoDeriveMcKEKey(KeyIdentifier_t keyID)1488 LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcKEKey( KeyIdentifier_t keyID )
1489 {
1490     // Prevent other keys than McRootKey
1491     if( keyID != MC_ROOT_KEY )
1492     {
1493         return LORAMAC_CRYPTO_ERROR_INVALID_KEY_ID;
1494     }
1495     uint8_t compBase[16] = { 0 };
1496 
1497     if( SecureElementDeriveAndStoreKey( compBase, keyID, MC_KE_KEY ) != SECURE_ELEMENT_SUCCESS )
1498     {
1499         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1500     }
1501 
1502     return LORAMAC_CRYPTO_SUCCESS;
1503 }
1504 
LoRaMacCryptoDeriveMcSessionKeyPair(AddressIdentifier_t addrID,uint32_t mcAddr)1505 LoRaMacCryptoStatus_t LoRaMacCryptoDeriveMcSessionKeyPair( AddressIdentifier_t addrID, uint32_t mcAddr )
1506 {
1507     if( mcAddr == 0 )
1508     {
1509         return LORAMAC_CRYPTO_ERROR_NPE;
1510     }
1511 
1512     LoRaMacCryptoStatus_t retval = LORAMAC_CRYPTO_ERROR;
1513 
1514     // Determine current security context
1515     KeyAddr_t* curItem;
1516     retval = GetKeyAddrItem( addrID, &curItem );
1517     if( retval != LORAMAC_CRYPTO_SUCCESS )
1518     {
1519         return retval;
1520     }
1521 
1522     // McAppSKey = aes128_encrypt(McKey, 0x01 | McAddr | pad16)
1523     // McNwkSKey = aes128_encrypt(McKey, 0x02 | McAddr | pad16)
1524 
1525     uint8_t compBaseAppS[16] = { 0 };
1526     uint8_t compBaseNwkS[16] = { 0 };
1527 
1528     compBaseAppS[0] = 0x01;
1529     compBaseAppS[1] = mcAddr & 0xFF;
1530     compBaseAppS[2] = ( mcAddr >> 8 ) & 0xFF;
1531     compBaseAppS[3] = ( mcAddr >> 16 ) & 0xFF;
1532     compBaseAppS[4] = ( mcAddr >> 24 ) & 0xFF;
1533 
1534     compBaseNwkS[0] = 0x02;
1535     compBaseNwkS[1] = mcAddr & 0xFF;
1536     compBaseNwkS[2] = ( mcAddr >> 8 ) & 0xFF;
1537     compBaseNwkS[3] = ( mcAddr >> 16 ) & 0xFF;
1538     compBaseNwkS[4] = ( mcAddr >> 24 ) & 0xFF;
1539 
1540     if( SecureElementDeriveAndStoreKey( compBaseAppS, curItem->RootKey, curItem->AppSkey ) != SECURE_ELEMENT_SUCCESS )
1541     {
1542         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1543     }
1544 
1545     if( SecureElementDeriveAndStoreKey( compBaseNwkS, curItem->RootKey, curItem->NwkSkey ) != SECURE_ELEMENT_SUCCESS )
1546     {
1547         return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
1548     }
1549 
1550     return LORAMAC_CRYPTO_SUCCESS;
1551 }
1552