Update LoRaMac-node to Version 4.4.4,fix Security breach found by Tencent Blade Team please refer to security advisory - CVE-2020-11068
fix Security breach found by Tencent Blade Team please refer to security advisory - CVE-2020-11068
This commit is contained in:
@@ -31,6 +31,10 @@
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if 1
|
||||
@@ -159,4 +163,8 @@ void aes_decrypt_256( const uint8_t in[N_BLOCK],
|
||||
uint8_t o_key[2 * N_BLOCK] );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -4,150 +4,151 @@ Copyright (C) 2009 Lander Casado, Philippas Tsigas
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files
|
||||
a copy of this software and associated documentation files
|
||||
(the "Software"), to deal with the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
the following conditions:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers. Redistributions in
|
||||
binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimers in the documentation and/or
|
||||
conditions and the following disclaimers in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
In no event shall the authors or copyright holders be liable for any special,
|
||||
incidental, indirect or consequential damages of any kind, or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether or not
|
||||
advised of the possibility of damage, and on any theory of liability,
|
||||
incidental, indirect or consequential damages of any kind, or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether or not
|
||||
advised of the possibility of damage, and on any theory of liability,
|
||||
arising out of or in connection with the use or performance of this software.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS WITH THE SOFTWARE
|
||||
|
||||
*****************************************************************************/
|
||||
//#include <sys/param.h>
|
||||
//#include <sys/systm.h>
|
||||
#include <stdint.h>
|
||||
#include "aes.h"
|
||||
#include "cmac.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#define LSHIFT(v, r) do { \
|
||||
int32_t i; \
|
||||
for (i = 0; i < 15; i++) \
|
||||
(r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \
|
||||
(r)[15] = (v)[15] << 1; \
|
||||
} while (0)
|
||||
|
||||
#define XOR(v, r) do { \
|
||||
int32_t i; \
|
||||
for (i = 0; i < 16; i++) \
|
||||
{ \
|
||||
(r)[i] = (r)[i] ^ (v)[i]; \
|
||||
} \
|
||||
} while (0) \
|
||||
#define LSHIFT( v, r ) \
|
||||
do \
|
||||
{ \
|
||||
int32_t i; \
|
||||
for( i = 0; i < 15; i++ ) \
|
||||
( r )[i] = ( v )[i] << 1 | ( v )[i + 1] >> 7; \
|
||||
( r )[15] = ( v )[15] << 1; \
|
||||
} while( 0 )
|
||||
|
||||
#define XOR( v, r ) \
|
||||
do \
|
||||
{ \
|
||||
int32_t i; \
|
||||
for( i = 0; i < 16; i++ ) \
|
||||
{ \
|
||||
( r )[i] = ( r )[i] ^ ( v )[i]; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
||||
void AES_CMAC_Init(AES_CMAC_CTX *ctx)
|
||||
void AES_CMAC_Init( AES_CMAC_CTX* ctx )
|
||||
{
|
||||
memset1(ctx->X, 0, sizeof ctx->X);
|
||||
ctx->M_n = 0;
|
||||
memset1(ctx->rijndael.ksch, '\0', 240);
|
||||
}
|
||||
|
||||
void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH])
|
||||
{
|
||||
//rijndael_set_key_enc_only(&ctx->rijndael, key, 128);
|
||||
aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael);
|
||||
}
|
||||
|
||||
void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t mlen;
|
||||
uint8_t in[16];
|
||||
|
||||
if (ctx->M_n > 0) {
|
||||
mlen = MIN(16 - ctx->M_n, len);
|
||||
memcpy1(ctx->M_last + ctx->M_n, data, mlen);
|
||||
ctx->M_n += mlen;
|
||||
if (ctx->M_n < 16 || len == mlen)
|
||||
return;
|
||||
XOR(ctx->M_last, ctx->X);
|
||||
//rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
|
||||
aes_encrypt( ctx->X, ctx->X, &ctx->rijndael);
|
||||
data += mlen;
|
||||
len -= mlen;
|
||||
}
|
||||
while (len > 16) { /* not last block */
|
||||
|
||||
XOR(data, ctx->X);
|
||||
//rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
|
||||
|
||||
memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
|
||||
aes_encrypt( in, in, &ctx->rijndael);
|
||||
memcpy1(&ctx->X[0], in, 16);
|
||||
|
||||
data += 16;
|
||||
len -= 16;
|
||||
}
|
||||
/* potential last block, save it */
|
||||
memcpy1(ctx->M_last, data, len);
|
||||
ctx->M_n = len;
|
||||
}
|
||||
|
||||
void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx)
|
||||
{
|
||||
uint8_t K[16];
|
||||
uint8_t in[16];
|
||||
/* generate subkey K1 */
|
||||
memset1(K, '\0', 16);
|
||||
|
||||
//rijndael_encrypt(&ctx->rijndael, K, K);
|
||||
|
||||
aes_encrypt( K, K, &ctx->rijndael);
|
||||
|
||||
if (K[0] & 0x80) {
|
||||
LSHIFT(K, K);
|
||||
K[15] ^= 0x87;
|
||||
} else
|
||||
LSHIFT(K, K);
|
||||
|
||||
|
||||
if (ctx->M_n == 16) {
|
||||
/* last block was a complete block */
|
||||
XOR(K, ctx->M_last);
|
||||
|
||||
} else {
|
||||
/* generate subkey K2 */
|
||||
if (K[0] & 0x80) {
|
||||
LSHIFT(K, K);
|
||||
K[15] ^= 0x87;
|
||||
} else
|
||||
LSHIFT(K, K);
|
||||
|
||||
/* padding(M_last) */
|
||||
ctx->M_last[ctx->M_n] = 0x80;
|
||||
while (++ctx->M_n < 16)
|
||||
ctx->M_last[ctx->M_n] = 0;
|
||||
|
||||
XOR(K, ctx->M_last);
|
||||
|
||||
|
||||
}
|
||||
XOR(ctx->M_last, ctx->X);
|
||||
|
||||
//rijndael_encrypt(&ctx->rijndael, ctx->X, digest);
|
||||
|
||||
memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
|
||||
aes_encrypt(in, digest, &ctx->rijndael);
|
||||
memset1(K, 0, sizeof K);
|
||||
|
||||
memset1( ctx->X, 0, sizeof ctx->X );
|
||||
ctx->M_n = 0;
|
||||
memset1( ctx->rijndael.ksch, '\0', 240 );
|
||||
}
|
||||
|
||||
void AES_CMAC_SetKey( AES_CMAC_CTX* ctx, const uint8_t key[AES_CMAC_KEY_LENGTH] )
|
||||
{
|
||||
aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael );
|
||||
}
|
||||
|
||||
void AES_CMAC_Update( AES_CMAC_CTX* ctx, const uint8_t* data, uint32_t len )
|
||||
{
|
||||
uint32_t mlen;
|
||||
uint8_t in[16];
|
||||
|
||||
if( ctx->M_n > 0 )
|
||||
{
|
||||
mlen = MIN( 16 - ctx->M_n, len );
|
||||
memcpy1( ctx->M_last + ctx->M_n, data, mlen );
|
||||
ctx->M_n += mlen;
|
||||
if( ctx->M_n < 16 || len == mlen )
|
||||
return;
|
||||
XOR( ctx->M_last, ctx->X );
|
||||
|
||||
memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
|
||||
aes_encrypt( in, in, &ctx->rijndael );
|
||||
memcpy1( &ctx->X[0], in, 16 );
|
||||
|
||||
data += mlen;
|
||||
len -= mlen;
|
||||
}
|
||||
while( len > 16 )
|
||||
{ /* not last block */
|
||||
|
||||
XOR( data, ctx->X );
|
||||
|
||||
memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
|
||||
aes_encrypt( in, in, &ctx->rijndael );
|
||||
memcpy1( &ctx->X[0], in, 16 );
|
||||
|
||||
data += 16;
|
||||
len -= 16;
|
||||
}
|
||||
/* potential last block, save it */
|
||||
memcpy1( ctx->M_last, data, len );
|
||||
ctx->M_n = len;
|
||||
}
|
||||
|
||||
void AES_CMAC_Final( uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX* ctx )
|
||||
{
|
||||
uint8_t K[16];
|
||||
uint8_t in[16];
|
||||
/* generate subkey K1 */
|
||||
memset1( K, '\0', 16 );
|
||||
|
||||
aes_encrypt( K, K, &ctx->rijndael );
|
||||
|
||||
if( K[0] & 0x80 )
|
||||
{
|
||||
LSHIFT( K, K );
|
||||
K[15] ^= 0x87;
|
||||
}
|
||||
else
|
||||
LSHIFT( K, K );
|
||||
|
||||
if( ctx->M_n == 16 )
|
||||
{
|
||||
/* last block was a complete block */
|
||||
XOR( K, ctx->M_last );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* generate subkey K2 */
|
||||
if( K[0] & 0x80 )
|
||||
{
|
||||
LSHIFT( K, K );
|
||||
K[15] ^= 0x87;
|
||||
}
|
||||
else
|
||||
LSHIFT( K, K );
|
||||
|
||||
/* padding(M_last) */
|
||||
ctx->M_last[ctx->M_n] = 0x80;
|
||||
while( ++ctx->M_n < 16 )
|
||||
ctx->M_last[ctx->M_n] = 0;
|
||||
|
||||
XOR( K, ctx->M_last );
|
||||
}
|
||||
XOR( ctx->M_last, ctx->X );
|
||||
|
||||
memcpy1( in, &ctx->X[0], 16 ); // Otherwise it does not look good
|
||||
aes_encrypt( in, digest, &ctx->rijndael );
|
||||
memset1( K, 0, sizeof K );
|
||||
}
|
||||
|
@@ -36,6 +36,10 @@ DEALINGS WITH THE SOFTWARE
|
||||
#ifndef _CMAC_H_
|
||||
#define _CMAC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
#define AES_CMAC_KEY_LENGTH 16
|
||||
@@ -59,5 +63,9 @@ void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *
|
||||
// __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH)));
|
||||
//__END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CMAC_H_ */
|
||||
|
||||
|
@@ -0,0 +1,297 @@
|
||||
/*!
|
||||
* \file se-identity.h
|
||||
*
|
||||
* \brief Secure Element identity and keys
|
||||
*
|
||||
* \copyright Revised BSD License, see section \ref LICENSE.
|
||||
*
|
||||
* \code
|
||||
* ______ _
|
||||
* / _____) _ | |
|
||||
* ( (____ _____ ____ _| |_ _____ ____| |__
|
||||
* \____ \| ___ | (_ _) ___ |/ ___) _ \
|
||||
* _____) ) ____| | | || |_| ____( (___| | | |
|
||||
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
|
||||
* (C)2020 Semtech
|
||||
*
|
||||
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
|
||||
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
|
||||
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|
||||
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
|
||||
* embedded.connectivity.solutions===============
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
#ifndef __SOFT_SE_IDENTITY_H__
|
||||
#define __SOFT_SE_IDENTITY_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
******************************************************************************
|
||||
********************************** WARNING ***********************************
|
||||
******************************************************************************
|
||||
The secure-element implementation supports both 1.0.x and 1.1.x LoRaWAN
|
||||
versions of the specification.
|
||||
Thus it has been decided to use the 1.1.x keys and EUI name definitions.
|
||||
The below table shows the names equivalence between versions:
|
||||
+---------------------+-------------------------+
|
||||
| 1.0.x | 1.1.x |
|
||||
+=====================+=========================+
|
||||
| LORAWAN_DEVICE_EUI | LORAWAN_DEVICE_EUI |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_APP_EUI | LORAWAN_JOIN_EUI |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_GEN_APP_KEY | LORAWAN_APP_KEY |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_APP_KEY | LORAWAN_NWK_KEY |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_NWK_S_KEY | LORAWAN_F_NWK_S_INT_KEY |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_NWK_S_KEY | LORAWAN_S_NWK_S_INT_KEY |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_NWK_S_KEY | LORAWAN_NWK_S_ENC_KEY |
|
||||
+---------------------+-------------------------+
|
||||
| LORAWAN_APP_S_KEY | LORAWAN_APP_S_KEY |
|
||||
+---------------------+-------------------------+
|
||||
******************************************************************************
|
||||
******************************************************************************
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/*!
|
||||
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
|
||||
* When set to 0 DevEui is automatically set with a value provided by MCU platform
|
||||
*/
|
||||
#define STATIC_DEVICE_EUI 0
|
||||
|
||||
/*!
|
||||
* end-device IEEE EUI (big endian)
|
||||
*/
|
||||
#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
/*!
|
||||
* App/Join server IEEE EUI (big endian)
|
||||
*/
|
||||
#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
/*!
|
||||
* Secure-element pin
|
||||
*/
|
||||
#define SECURE_ELEMENT_PIN { 0x00, 0x00, 0x00, 0x00 }
|
||||
|
||||
/*!
|
||||
* When set to 1 DevAddr is LORAWAN_DEVICE_ADDRESS
|
||||
* When set to 0 DevAddr is automatically set with a value provided by a pseudo
|
||||
* random generator seeded with a value provided by the MCU platform
|
||||
*/
|
||||
#define STATIC_DEVICE_ADDRESS 0
|
||||
|
||||
/*!
|
||||
* Device address on the network (big endian)
|
||||
*/
|
||||
#define LORAWAN_DEVICE_ADDRESS ( uint32_t )0x00000000
|
||||
|
||||
#define SOFT_SE_KEY_LIST \
|
||||
{ \
|
||||
{ \
|
||||
/*! \
|
||||
* Application root key \
|
||||
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
|
||||
*/ \
|
||||
.KeyID = APP_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Network root key \
|
||||
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
|
||||
*/ \
|
||||
.KeyID = NWK_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Join session integrity key (Dynamically updated) \
|
||||
* WARNING: NOT USED FOR 1.0.x DEVICES \
|
||||
*/ \
|
||||
.KeyID = J_S_INT_KEY, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Join session encryption key (Dynamically updated) \
|
||||
* WARNING: NOT USED FOR 1.0.x DEVICES \
|
||||
*/ \
|
||||
.KeyID = J_S_ENC_KEY, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Forwarding Network session integrity key \
|
||||
* WARNING: NWK_S_KEY FOR 1.0.x DEVICES \
|
||||
*/ \
|
||||
.KeyID = F_NWK_S_INT_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Serving Network session integrity key \
|
||||
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
|
||||
*/ \
|
||||
.KeyID = S_NWK_S_INT_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Network session encryption key \
|
||||
* WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \
|
||||
*/ \
|
||||
.KeyID = NWK_S_ENC_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Application session key \
|
||||
*/ \
|
||||
.KeyID = APP_S_KEY, \
|
||||
.KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \
|
||||
0x3C }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast root key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_ROOT_KEY, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast key encryption key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_KE_KEY, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #0 root key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_KEY_0, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #0 application session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_APP_S_KEY_0, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #0 network session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_NWK_S_KEY_0, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #1 root key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_KEY_1, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #1 application session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_APP_S_KEY_1, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #1 network session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_NWK_S_KEY_1, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #2 root key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_KEY_2, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #2 application session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_APP_S_KEY_2, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #2 network session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_NWK_S_KEY_2, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #3 root key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_KEY_3, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #3 application session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_APP_S_KEY_3, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* Multicast group #3 network session key (Dynamically updated) \
|
||||
*/ \
|
||||
.KeyID = MC_NWK_S_KEY_3, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
{ \
|
||||
/*! \
|
||||
* All zeros key. (ClassB usage)(constant) \
|
||||
*/ \
|
||||
.KeyID = SLOT_RAND_ZERO_KEY, \
|
||||
.KeyValue = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00 }, \
|
||||
}, \
|
||||
},
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __SOFT_SE_IDENTITY_H__
|
@@ -0,0 +1,39 @@
|
||||
/*!
|
||||
* \file soft-se-hal.h
|
||||
*
|
||||
* \brief Secure Element hardware abstraction layer implementation
|
||||
*
|
||||
* \copyright Revised BSD License, see section \ref LICENSE.
|
||||
*
|
||||
* \code
|
||||
* ______ _
|
||||
* / _____) _ | |
|
||||
* ( (____ _____ ____ _| |_ _____ ____| |__
|
||||
* \____ \| ___ | (_ _) ___ |/ ___) _ \
|
||||
* _____) ) ____| | | || |_| ____( (___| | | |
|
||||
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
|
||||
* (C)2020 Semtech
|
||||
*
|
||||
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
|
||||
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
|
||||
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|
||||
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
|
||||
* embedded.connectivity.solutions===============
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
#include "board.h"
|
||||
#include "radio.h"
|
||||
|
||||
#include "soft-se-hal.h"
|
||||
|
||||
void SoftSeHalGetUniqueId( uint8_t *id )
|
||||
{
|
||||
BoardGetUniqueId( id );
|
||||
}
|
||||
|
||||
uint32_t SoftSeHalGetRandomNumber( void )
|
||||
{
|
||||
return Radio.Random( );
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*!
|
||||
* \file soft-se-hal.h
|
||||
*
|
||||
* \brief Secure Element hardware abstraction layer
|
||||
*
|
||||
* \copyright Revised BSD License, see section \ref LICENSE.
|
||||
*
|
||||
* \code
|
||||
* ______ _
|
||||
* / _____) _ | |
|
||||
* ( (____ _____ ____ _| |_ _____ ____| |__
|
||||
* \____ \| ___ | (_ _) ___ |/ ___) _ \
|
||||
* _____) ) ____| | | || |_| ____( (___| | | |
|
||||
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
|
||||
* (C)2020 Semtech
|
||||
*
|
||||
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
|
||||
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
|
||||
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|
||||
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
|
||||
* embedded.connectivity.solutions===============
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
#ifndef __SOFT_SE_HAL_H__
|
||||
#define __SOFT_SE_HAL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*!
|
||||
* \brief Get a 64 bits unique ID
|
||||
*
|
||||
* \param [IN] id Pointer to an array that will contain the Unique ID
|
||||
*/
|
||||
void SoftSeHalGetUniqueId( uint8_t *id );
|
||||
|
||||
/*!
|
||||
* \brief Get a random number
|
||||
*
|
||||
* \remark The number SHALL NOT be generated using a pseudo random number
|
||||
* generator
|
||||
* \retval number 32 bit random value
|
||||
*/
|
||||
uint32_t SoftSeHalGetRandomNumber( void );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __SOFT_SE_HAL_H__
|
@@ -1,36 +1,45 @@
|
||||
/*
|
||||
/ _____) _ | |
|
||||
( (____ _____ ____ _| |_ _____ ____| |__
|
||||
\____ \| ___ | (_ _) ___ |/ ___) _ \
|
||||
_____) ) ____| | | || |_| ____( (___| | | |
|
||||
(______/|_____)_|_|_| \__)_____)\____)_| |_|
|
||||
(C)2013 Semtech
|
||||
___ _____ _ ___ _ _____ ___ ___ ___ ___
|
||||
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
|
||||
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|
||||
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
|
||||
embedded.connectivity.solutions===============
|
||||
|
||||
Description: Secure Element software implementation
|
||||
|
||||
License: Revised BSD License, see LICENSE.TXT file include in the project
|
||||
|
||||
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ),
|
||||
Daniel Jaeckle ( STACKFORCE ), Johannes Bruder ( STACKFORCE )
|
||||
*/
|
||||
#include "secure-element.h"
|
||||
|
||||
/*!
|
||||
* \file soft-se.c
|
||||
*
|
||||
* \brief Secure Element software implementation
|
||||
*
|
||||
* \copyright Revised BSD License, see section \ref LICENSE.
|
||||
*
|
||||
* \code
|
||||
* ______ _
|
||||
* / _____) _ | |
|
||||
* ( (____ _____ ____ _| |_ _____ ____| |__
|
||||
* \____ \| ___ | (_ _) ___ |/ ___) _ \
|
||||
* _____) ) ____| | | || |_| ____( (___| | | |
|
||||
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
|
||||
* (C)2020 Semtech
|
||||
*
|
||||
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
|
||||
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
|
||||
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|
||||
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
|
||||
* embedded.connectivity.solutions===============
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "LoRaMacCrypto.h"
|
||||
#include "utilities.h"
|
||||
#include "aes.h"
|
||||
#include "cmac.h"
|
||||
#include "radio.h"
|
||||
|
||||
#define NUM_OF_KEYS 22
|
||||
#define KEY_SIZE 16
|
||||
#include "LoRaMacHeaderTypes.h"
|
||||
|
||||
#include "secure-element.h"
|
||||
#include "se-identity.h"
|
||||
#include "soft-se-hal.h"
|
||||
|
||||
/*!
|
||||
* Number of supported crypto keys
|
||||
*/
|
||||
#define NUM_OF_KEYS 23
|
||||
|
||||
/*!
|
||||
* Identifier value pair type for Keys
|
||||
@@ -44,7 +53,7 @@ typedef struct sKey
|
||||
/*
|
||||
* Key value
|
||||
*/
|
||||
uint8_t KeyValue[KEY_SIZE];
|
||||
uint8_t KeyValue[SE_KEY_SIZE];
|
||||
} Key_t;
|
||||
|
||||
/*
|
||||
@@ -53,25 +62,49 @@ typedef struct sKey
|
||||
typedef struct sSecureElementNvCtx
|
||||
{
|
||||
/*
|
||||
* AES computation context variable
|
||||
* DevEUI storage
|
||||
*/
|
||||
aes_context AesContext;
|
||||
uint8_t DevEui[SE_EUI_SIZE];
|
||||
/*
|
||||
* CMAC computation context variable
|
||||
* Join EUI storage
|
||||
*/
|
||||
AES_CMAC_CTX AesCmacCtx[1];
|
||||
uint8_t JoinEui[SE_EUI_SIZE];
|
||||
/*
|
||||
* Pin storage
|
||||
*/
|
||||
uint8_t Pin[SE_PIN_SIZE];
|
||||
/*
|
||||
* Key List
|
||||
*/
|
||||
Key_t KeyList[NUM_OF_KEYS];
|
||||
}SecureElementNvCtx_t;
|
||||
} SecureElementNvCtx_t;
|
||||
|
||||
/*
|
||||
* Module context
|
||||
/*!
|
||||
* Secure element context
|
||||
*/
|
||||
static SecureElementNvCtx_t SeNvmCtx;
|
||||
static SecureElementNvCtx_t SeNvmCtx = {
|
||||
/*!
|
||||
* end-device IEEE EUI (big endian)
|
||||
*
|
||||
* \remark In this application the value is automatically generated by calling
|
||||
* BoardGetUniqueId function
|
||||
*/
|
||||
.DevEui = LORAWAN_DEVICE_EUI,
|
||||
/*!
|
||||
* App/Join server IEEE EUI (big endian)
|
||||
*/
|
||||
.JoinEui = LORAWAN_JOIN_EUI,
|
||||
/*!
|
||||
* Secure-element pin (big endian)
|
||||
*/
|
||||
.Pin = SECURE_ELEMENT_PIN,
|
||||
/*!
|
||||
* LoRaWAN key list
|
||||
*/
|
||||
.KeyList = SOFT_SE_KEY_LIST
|
||||
};
|
||||
|
||||
static EventNvmCtxChanged SeNvmCtxChanged;
|
||||
static SecureElementNvmEvent SeNvmCtxChanged;
|
||||
|
||||
/*
|
||||
* Local functions
|
||||
@@ -80,13 +113,11 @@ static EventNvmCtxChanged SeNvmCtxChanged;
|
||||
/*
|
||||
* Gets key item from key list.
|
||||
*
|
||||
* cmac = aes128_cmac(keyID, B0 | msg)
|
||||
*
|
||||
* \param[IN] keyID - Key identifier
|
||||
* \param[OUT] keyItem - Key item reference
|
||||
* \retval - Status of the operation
|
||||
*/
|
||||
SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
|
||||
static SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
|
||||
{
|
||||
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
|
||||
{
|
||||
@@ -99,44 +130,6 @@ SecureElementStatus_t GetKeyByID( KeyIdentifier_t keyID, Key_t** keyItem )
|
||||
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes a CMAC
|
||||
*
|
||||
* \param[IN] buffer - Data buffer
|
||||
* \param[IN] size - Data buffer size
|
||||
* \param[IN] keyID - Key identifier to determine the AES key to be used
|
||||
* \param[OUT] cmac - Computed cmac
|
||||
* \retval - Status of the operation
|
||||
*/
|
||||
SecureElementStatus_t ComputeCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac )
|
||||
{
|
||||
if( buffer == NULL || cmac == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
|
||||
uint8_t Cmac[16];
|
||||
|
||||
AES_CMAC_Init( SeNvmCtx.AesCmacCtx );
|
||||
|
||||
Key_t* keyItem;
|
||||
SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
|
||||
|
||||
if( retval == SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
AES_CMAC_SetKey( SeNvmCtx.AesCmacCtx, keyItem->KeyValue );
|
||||
|
||||
AES_CMAC_Update( SeNvmCtx.AesCmacCtx, buffer, size );
|
||||
|
||||
AES_CMAC_Final( Cmac, SeNvmCtx.AesCmacCtx );
|
||||
|
||||
// Bring into the required format
|
||||
*cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 | ( uint32_t ) Cmac[0] );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy callback in case if the user provides NULL function pointer
|
||||
*/
|
||||
@@ -145,37 +138,61 @@ static void DummyCB( void )
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Computes a CMAC of a message using provided initial Bx block
|
||||
*
|
||||
* cmac = aes128_cmac(keyID, blocks[i].Buffer)
|
||||
*
|
||||
* \param[IN] micBxBuffer - Buffer containing the initial Bx block
|
||||
* \param[IN] buffer - Data buffer
|
||||
* \param[IN] size - Data buffer size
|
||||
* \param[IN] keyID - Key identifier to determine the AES key to be used
|
||||
* \param[OUT] cmac - Computed cmac
|
||||
* \retval - Status of the operation
|
||||
*/
|
||||
static SecureElementStatus_t ComputeCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
|
||||
uint32_t* cmac )
|
||||
{
|
||||
if( ( buffer == NULL ) || ( cmac == NULL ) )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
|
||||
uint8_t Cmac[16];
|
||||
AES_CMAC_CTX aesCmacCtx[1];
|
||||
|
||||
AES_CMAC_Init( aesCmacCtx );
|
||||
|
||||
Key_t* keyItem;
|
||||
SecureElementStatus_t retval = GetKeyByID( keyID, &keyItem );
|
||||
|
||||
if( retval == SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
AES_CMAC_SetKey( aesCmacCtx, keyItem->KeyValue );
|
||||
|
||||
if( micBxBuffer != NULL )
|
||||
{
|
||||
AES_CMAC_Update( aesCmacCtx, micBxBuffer, 16 );
|
||||
}
|
||||
|
||||
AES_CMAC_Update( aesCmacCtx, buffer, size );
|
||||
|
||||
AES_CMAC_Final( Cmac, aesCmacCtx );
|
||||
|
||||
// Bring into the required format
|
||||
*cmac = ( uint32_t )( ( uint32_t ) Cmac[3] << 24 | ( uint32_t ) Cmac[2] << 16 | ( uint32_t ) Cmac[1] << 8 |
|
||||
( uint32_t ) Cmac[0] );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* API functions
|
||||
*/
|
||||
|
||||
SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged )
|
||||
SecureElementStatus_t SecureElementInit( SecureElementNvmEvent seNvmCtxChanged )
|
||||
{
|
||||
// Initialize with defaults
|
||||
uint8_t itr = 0;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = APP_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = NWK_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = J_S_INT_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = J_S_ENC_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = F_NWK_S_INT_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = S_NWK_S_INT_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = NWK_S_ENC_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = APP_S_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_KE_KEY;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_0;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_0;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_0;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_1;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_1;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_1;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_2;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_2;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_2;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_KEY_3;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_APP_S_KEY_3;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = MC_NWK_S_KEY_3;
|
||||
SeNvmCtx.KeyList[itr++].KeyID = SLOT_RAND_ZERO_KEY;
|
||||
|
||||
// Assign callback
|
||||
if( seNvmCtxChanged != 0 )
|
||||
{
|
||||
@@ -186,6 +203,15 @@ SecureElementStatus_t SecureElementInit( EventNvmCtxChanged seNvmCtxChanged )
|
||||
SeNvmCtxChanged = DummyCB;
|
||||
}
|
||||
|
||||
#if !defined( SECURE_ELEMENT_PRE_PROVISIONED )
|
||||
#if( STATIC_DEVICE_EUI == 0 )
|
||||
// Get a DevEUI from MCU unique ID
|
||||
SoftSeHalGetUniqueId( SeNvmCtx.DevEui );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SeNvmCtxChanged( );
|
||||
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -215,26 +241,26 @@ SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
|
||||
|
||||
for( uint8_t i = 0; i < NUM_OF_KEYS; i++ )
|
||||
{
|
||||
if( SeNvmCtx.KeyList[i].KeyID == keyID )
|
||||
{
|
||||
if( LORAMAC_CRYPTO_MULITCAST_KEYS < SeNvmCtx.KeyList[i].KeyID )
|
||||
{ // Decrypt the key if its a Mulitcast key
|
||||
|
||||
uint8_t decryptedKey[16] = { 0 };
|
||||
if( ( keyID == MC_KEY_0 ) || ( keyID == MC_KEY_1 ) || ( keyID == MC_KEY_2 ) || ( keyID == MC_KEY_3 ) )
|
||||
{ // Decrypt the key if its a Mckey
|
||||
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
|
||||
uint8_t decryptedKey[16] = { 0 };
|
||||
|
||||
retval = SecureElementAesEncrypt( key, 16, MC_KE_KEY, decryptedKey );
|
||||
if( retval != SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
memcpy1( SeNvmCtx.KeyList[i].KeyValue, decryptedKey, SE_KEY_SIZE );
|
||||
SeNvmCtxChanged( );
|
||||
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy1( SeNvmCtx.KeyList[i].KeyValue, key, KEY_SIZE );
|
||||
memcpy1( SeNvmCtx.KeyList[i].KeyValue, key, SE_KEY_SIZE );
|
||||
SeNvmCtxChanged( );
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
@@ -244,28 +270,29 @@ SecureElementStatus_t SecureElementSetKey( KeyIdentifier_t keyID, uint8_t* key )
|
||||
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint32_t* cmac )
|
||||
SecureElementStatus_t SecureElementComputeAesCmac( uint8_t* micBxBuffer, uint8_t* buffer, uint16_t size,
|
||||
KeyIdentifier_t keyID, uint32_t* cmac )
|
||||
{
|
||||
if( keyID >= LORAMAC_CRYPTO_MULITCAST_KEYS )
|
||||
if( keyID >= LORAMAC_CRYPTO_MULTICAST_KEYS )
|
||||
{
|
||||
//Never accept multicast key identifier for cmac computation
|
||||
// Never accept multicast key identifier for cmac computation
|
||||
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
|
||||
}
|
||||
|
||||
return ComputeCmac( buffer, size, keyID, cmac );
|
||||
return ComputeCmac( micBxBuffer, buffer, size, keyID, cmac );
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac, KeyIdentifier_t keyID )
|
||||
SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size, uint32_t expectedCmac,
|
||||
KeyIdentifier_t keyID )
|
||||
{
|
||||
if( buffer == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
|
||||
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
|
||||
uint32_t compCmac = 0;
|
||||
|
||||
retval = ComputeCmac( buffer, size, keyID, &compCmac );
|
||||
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
|
||||
uint32_t compCmac = 0;
|
||||
retval = ComputeCmac( NULL, buffer, size, keyID, &compCmac );
|
||||
if( retval != SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
return retval;
|
||||
@@ -279,7 +306,8 @@ SecureElementStatus_t SecureElementVerifyAesCmac( uint8_t* buffer, uint16_t size
|
||||
return retval;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID, uint8_t* encBuffer )
|
||||
SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, KeyIdentifier_t keyID,
|
||||
uint8_t* encBuffer )
|
||||
{
|
||||
if( buffer == NULL || encBuffer == NULL )
|
||||
{
|
||||
@@ -292,55 +320,48 @@ SecureElementStatus_t SecureElementAesEncrypt( uint8_t* buffer, uint16_t size, K
|
||||
return SECURE_ELEMENT_ERROR_BUF_SIZE;
|
||||
}
|
||||
|
||||
memset1( SeNvmCtx.AesContext.ksch, '\0', 240 );
|
||||
aes_context aesContext;
|
||||
memset1( aesContext.ksch, '\0', 240 );
|
||||
|
||||
Key_t* pItem;
|
||||
Key_t* pItem;
|
||||
SecureElementStatus_t retval = GetKeyByID( keyID, &pItem );
|
||||
|
||||
if( retval == SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
aes_set_key( pItem->KeyValue, 16, &SeNvmCtx.AesContext );
|
||||
aes_set_key( pItem->KeyValue, 16, &aesContext );
|
||||
|
||||
uint8_t block = 0;
|
||||
|
||||
while( size != 0 )
|
||||
{
|
||||
aes_encrypt( &buffer[block], &encBuffer[block], &SeNvmCtx.AesContext );
|
||||
aes_encrypt( &buffer[block], &encBuffer[block], &aesContext );
|
||||
block = block + 16;
|
||||
size = size - 16;
|
||||
size = size - 16;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID, KeyIdentifier_t targetKeyID )
|
||||
SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t* input, KeyIdentifier_t rootKeyID,
|
||||
KeyIdentifier_t targetKeyID )
|
||||
{
|
||||
if( input == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
|
||||
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
|
||||
uint8_t key[16] = { 0 };
|
||||
SecureElementStatus_t retval = SECURE_ELEMENT_ERROR;
|
||||
uint8_t key[16] = { 0 };
|
||||
|
||||
// In case of MC_KE_KEY, prevent other keys than NwkKey or AppKey for LoRaWAN 1.1 or later
|
||||
// In case of MC_KE_KEY, only McRootKey can be used as root key
|
||||
if( targetKeyID == MC_KE_KEY )
|
||||
{
|
||||
if( ( ( rootKeyID == APP_KEY ) && ( version.Fields.Minor == 0 ) ) || ( rootKeyID == NWK_KEY ) )
|
||||
if( rootKeyID != MC_ROOT_KEY )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_INVALID_KEY_ID;
|
||||
}
|
||||
}
|
||||
|
||||
// In case of McKEKey derivation, the parameter input is concatenated: nonce | DevEUI | pad16
|
||||
// where nonce SHALL be greater than 15
|
||||
uint16_t nonce = input[0];
|
||||
nonce |= ( ( uint16_t ) input[1] << 8 );
|
||||
if( ( targetKeyID == MC_KE_KEY ) && ( nonce < 16 ) )
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Derive key
|
||||
retval = SecureElementAesEncrypt( input, 16, rootKeyID, key );
|
||||
if( retval != SECURE_ELEMENT_SUCCESS )
|
||||
@@ -358,12 +379,159 @@ SecureElementStatus_t SecureElementDeriveAndStoreKey( Version_t version, uint8_t
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementProcessJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEui,
|
||||
uint16_t devNonce, uint8_t* encJoinAccept,
|
||||
uint8_t encJoinAcceptSize, uint8_t* decJoinAccept,
|
||||
uint8_t* versionMinor )
|
||||
{
|
||||
if( ( encJoinAccept == NULL ) || ( decJoinAccept == NULL ) || ( versionMinor == NULL ) )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
|
||||
// Check that frame size isn't bigger than a JoinAccept with CFList size
|
||||
if( encJoinAcceptSize > LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_BUF_SIZE;
|
||||
}
|
||||
|
||||
// Determine decryption key
|
||||
KeyIdentifier_t encKeyID = NWK_KEY;
|
||||
|
||||
if( joinReqType != JOIN_REQ )
|
||||
{
|
||||
encKeyID = J_S_ENC_KEY;
|
||||
}
|
||||
|
||||
memcpy1( decJoinAccept, encJoinAccept, encJoinAcceptSize );
|
||||
|
||||
// Decrypt JoinAccept, skip MHDR
|
||||
if( SecureElementAesEncrypt( encJoinAccept + LORAMAC_MHDR_FIELD_SIZE, encJoinAcceptSize - LORAMAC_MHDR_FIELD_SIZE,
|
||||
encKeyID, decJoinAccept + LORAMAC_MHDR_FIELD_SIZE ) != SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
return SECURE_ELEMENT_FAIL_ENCRYPT;
|
||||
}
|
||||
|
||||
*versionMinor = ( ( decJoinAccept[11] & 0x80 ) == 0x80 ) ? 1 : 0;
|
||||
|
||||
uint32_t mic = 0;
|
||||
|
||||
mic = ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE] << 0 );
|
||||
mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 1] << 8 );
|
||||
mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 2] << 16 );
|
||||
mic |= ( ( uint32_t ) decJoinAccept[encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE + 3] << 24 );
|
||||
|
||||
// - Header buffer to be used for MIC computation
|
||||
// - LoRaWAN 1.0.x : micHeader = [MHDR(1)]
|
||||
// - LoRaWAN 1.1.x : micHeader = [JoinReqType(1), JoinEUI(8), DevNonce(2), MHDR(1)]
|
||||
|
||||
// Verify mic
|
||||
if( *versionMinor == 0 )
|
||||
{
|
||||
// For LoRaWAN 1.0.x
|
||||
// cmac = aes128_cmac(NwkKey, MHDR | JoinNonce | NetID | DevAddr | DLSettings | RxDelay | CFList |
|
||||
// CFListType)
|
||||
if( SecureElementVerifyAesCmac( decJoinAccept, ( encJoinAcceptSize - LORAMAC_MIC_FIELD_SIZE ), mic, NWK_KEY ) !=
|
||||
SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
return SECURE_ELEMENT_FAIL_CMAC;
|
||||
}
|
||||
}
|
||||
#if( USE_LRWAN_1_1_X_CRYPTO == 1 )
|
||||
else if( *versionMinor == 1 )
|
||||
{
|
||||
uint8_t micHeader11[JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
|
||||
uint16_t bufItr = 0;
|
||||
|
||||
micHeader11[bufItr++] = ( uint8_t ) joinReqType;
|
||||
|
||||
memcpyr( micHeader11 + bufItr, joinEui, LORAMAC_JOIN_EUI_FIELD_SIZE );
|
||||
bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;
|
||||
|
||||
micHeader11[bufItr++] = devNonce & 0xFF;
|
||||
micHeader11[bufItr++] = ( devNonce >> 8 ) & 0xFF;
|
||||
|
||||
// For LoRaWAN 1.1.x and later:
|
||||
// cmac = aes128_cmac(JSIntKey, JoinReqType | JoinEUI | DevNonce | MHDR | JoinNonce | NetID | DevAddr |
|
||||
// DLSettings | RxDelay | CFList | CFListType)
|
||||
// Prepare the msg for integrity check (adding JoinReqType, JoinEUI and DevNonce)
|
||||
uint8_t localBuffer[LORAMAC_JOIN_ACCEPT_FRAME_MAX_SIZE + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET] = { 0 };
|
||||
|
||||
memcpy1( localBuffer, micHeader11, JOIN_ACCEPT_MIC_COMPUTATION_OFFSET );
|
||||
memcpy1( localBuffer + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET - 1, decJoinAccept, encJoinAcceptSize );
|
||||
|
||||
if( SecureElementVerifyAesCmac( localBuffer,
|
||||
encJoinAcceptSize + JOIN_ACCEPT_MIC_COMPUTATION_OFFSET -
|
||||
LORAMAC_MHDR_FIELD_SIZE - LORAMAC_MIC_FIELD_SIZE,
|
||||
mic, J_S_INT_KEY ) != SECURE_ELEMENT_SUCCESS )
|
||||
{
|
||||
return SECURE_ELEMENT_FAIL_CMAC;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_INVALID_LORAWAM_SPEC_VERSION;
|
||||
}
|
||||
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementRandomNumber( uint32_t* randomNum )
|
||||
{
|
||||
if( randomNum == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
*randomNum = Radio.Random( );
|
||||
*randomNum = SoftSeHalGetRandomNumber( );
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementSetDevEui( uint8_t* devEui )
|
||||
{
|
||||
if( devEui == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
memcpy1( SeNvmCtx.DevEui, devEui, SE_EUI_SIZE );
|
||||
SeNvmCtxChanged( );
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t* SecureElementGetDevEui( void )
|
||||
{
|
||||
return SeNvmCtx.DevEui;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementSetJoinEui( uint8_t* joinEui )
|
||||
{
|
||||
if( joinEui == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
memcpy1( SeNvmCtx.JoinEui, joinEui, SE_EUI_SIZE );
|
||||
SeNvmCtxChanged( );
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t* SecureElementGetJoinEui( void )
|
||||
{
|
||||
return SeNvmCtx.JoinEui;
|
||||
}
|
||||
|
||||
SecureElementStatus_t SecureElementSetPin( uint8_t* pin )
|
||||
{
|
||||
if( pin == NULL )
|
||||
{
|
||||
return SECURE_ELEMENT_ERROR_NPE;
|
||||
}
|
||||
|
||||
memcpy1( SeNvmCtx.Pin, pin, SE_PIN_SIZE );
|
||||
SeNvmCtxChanged( );
|
||||
return SECURE_ELEMENT_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t* SecureElementGetPin( void )
|
||||
{
|
||||
return SeNvmCtx.Pin;
|
||||
}
|
||||
|
Reference in New Issue
Block a user