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 break;
686 case A_FCNT_DOWN:
687 *lastDown = CryptoNvm->FCntList.AFCntDown;
688 break;
689 case FCNT_DOWN:
690 *lastDown = CryptoNvm->FCntList.FCntDown;
691 break;
692 #if ( LORAMAC_MAX_MC_CTX > 0 )
693 case MC_FCNT_DOWN_0:
694 *lastDown = CryptoNvm->FCntList.McFCntDown[0];
695 break;
696 #endif
697 #if ( LORAMAC_MAX_MC_CTX > 1 )
698 case MC_FCNT_DOWN_1:
699 *lastDown = CryptoNvm->FCntList.McFCntDown[1];
700 break;
701 #endif
702 #if ( LORAMAC_MAX_MC_CTX > 2 )
703 case MC_FCNT_DOWN_2:
704 *lastDown = CryptoNvm->FCntList.McFCntDown[2];
705 break;
706 #endif
707 #if ( LORAMAC_MAX_MC_CTX > 3 )
708 case MC_FCNT_DOWN_3:
709 *lastDown = CryptoNvm->FCntList.McFCntDown[3];
710 break;
711 #endif
712 default:
713 return LORAMAC_CRYPTO_FAIL_FCNT_ID;
714 }
715 return LORAMAC_CRYPTO_SUCCESS;
716 }
717
718 /*
719 * Checks the downlink counter value
720 *
721 * \param[IN] fCntID - Frame counter identifier
722 * \param[IN] currentDown - Current downlink counter value
723 *
724 * \retval - Status of the operation
725 */
CheckFCntDown(FCntIdentifier_t fCntID,uint32_t currentDown)726 static bool CheckFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
727 {
728 uint32_t lastDown = 0;
729 if( GetLastFcntDown( fCntID, &lastDown ) != LORAMAC_CRYPTO_SUCCESS )
730 {
731 return false;
732 }
733 if( ( currentDown > lastDown ) ||
734 // For LoRaWAN 1.0.X only. Allow downlink frames of 0
735 ( lastDown == FCNT_DOWN_INITIAL_VALUE ) )
736 {
737 return true;
738 }
739 else
740 {
741 return false;
742 }
743 }
744
745 /*!
746 * Updates the reference downlink counter
747 *
748 * \param[IN] fCntID - Frame counter identifier
749 * \param[IN] currentDown - Current downlink counter value
750 *
751 * \retval - Status of the operation
752 */
UpdateFCntDown(FCntIdentifier_t fCntID,uint32_t currentDown)753 static void UpdateFCntDown( FCntIdentifier_t fCntID, uint32_t currentDown )
754 {
755 switch( fCntID )
756 {
757 case N_FCNT_DOWN:
758 CryptoNvm->FCntList.NFCntDown = currentDown;
759 CryptoNvm->LastDownFCnt = currentDown;
760 break;
761 case A_FCNT_DOWN:
762 CryptoNvm->FCntList.AFCntDown = currentDown;
763 CryptoNvm->LastDownFCnt = currentDown;
764 break;
765 case FCNT_DOWN:
766 CryptoNvm->FCntList.FCntDown = currentDown;
767 CryptoNvm->LastDownFCnt = 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_INITIAL_VALUE;
801 CryptoNvm->FCntList.AFCntDown = FCNT_DOWN_INITIAL_VALUE;
802 CryptoNvm->FCntList.FCntDown = FCNT_DOWN_INITIAL_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_INITIAL_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_INITIAL_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_INITIAL_VALUE;
1281 CryptoNvm->FCntList.NFCntDown = FCNT_DOWN_INITIAL_VALUE;
1282 CryptoNvm->FCntList.AFCntDown = FCNT_DOWN_INITIAL_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