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