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