Skip to content

Instantly share code, notes, and snippets.

@n-eq
Last active October 4, 2017 20:23
Show Gist options
  • Save n-eq/a565089785a1f94f3422928a3e6e5b98 to your computer and use it in GitHub Desktop.
Save n-eq/a565089785a1f94f3422928a3e6e5b98 to your computer and use it in GitHub Desktop.
A C program to calculate LoRaWAN's Network Session Key (NwSKey) using mbed TLS
/*
* This C program calculates LoRaWAN's network session key (NwkSKey) using
* mbed TLS.
* To use it, you should provide the following parameters in this order when
* executing the program:
* AppKey: An AES-128 key
* AppNonce: A random 3 byte value
* NetID: A network identifier
* DevNonce: A 2 byte nonce
* Example:
* ./nwkskey 0x4F34BF40BFFF839D07FC62DEFA24D185 0x15AE9F 0x8A34DD 0x5519
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include "mbedtls/aes.h"
#define ARGC 5
#define KEY_LEN 16
#define KEY_SIZE 128
#define USAGE \
"\nUsage: ./nwkskey <AppKey> <AppNonce> <NetID> <DevNonce>\n\n"
static mbedtls_aes_context aes_ctx;
int main(int argc, char* argv[]){
if (argc != ARGC){
fprintf(stderr, USAGE);
exit(EXIT_FAILURE);
}
assert(argc == ARGC);
// Define this loop internal variable to avoid c99/gnu99 compatibility errors
int i;
unsigned char app_key[KEY_LEN];
unsigned char input[KEY_LEN];
unsigned char nwkskey[KEY_LEN];
// Cast the parameters to void* in order to avoid memset argument
// type warnings
memset(input, 0, sizeof(input));
memset(nwkskey, 0, sizeof(nwkskey));
memset(app_key, 0, sizeof(app_key));
// Parse AppKey from the first command line argument
unsigned char* p;
p = &argv[1][0];
// shift the pointer if the hex number starts with a "0[X|x]" pattern
if ((strncmp(argv[1], "0x", 2) == 0) || (strncmp(argv[1], "0X", 2)))
p += 2;
i = 0;
unsigned char tmp;
while ((sscanf(p, "%X", &tmp) > 0) && (i < KEY_LEN)){
app_key[KEY_LEN - i++] = tmp; // data stored in little endian mode
p++;
}
// Parse input parameters from the command line arguments
uint32_t app_nonce = 0, net_id = 0;
uint16_t dev_nonce = 0;
sscanf(argv[2], "%X", &app_nonce);
sscanf(argv[3], "%X", &net_id);
sscanf(argv[4], "%X", &dev_nonce);
// An alternative may be using an array of pointers (void* p[])
// and sscanf'ing in a loop
// Build up the input (data are stored in little endian (network byte order)
input[0] = 0x1;
input[1] = (unsigned char) (app_nonce & 0xFF);
input[2] = (unsigned char) ((app_nonce >> 8) & 0xFF);
input[3] = (unsigned char) ((app_nonce >> 16) & 0xFF);
input[4] = (unsigned char) (net_id & 0xFF);
input[5] = (unsigned char) ((net_id >> 8) & 0xFF);
input[6] = (unsigned char) ((net_id >> 16) & 0xFF);
input[7] = (unsigned char) (dev_nonce & 0xFF);
input[8] = (unsigned char) ((dev_nonce >> 8) & 0xFF);
mbedtls_aes_init(&aes_ctx);
mbedtls_aes_setkey_enc(&aes_ctx, app_key, KEY_SIZE);
mbedtls_aes_encrypt(&aes_ctx, input, nwkskey);
printf("Network Session Key: ");
for (i = 0; i < KEY_LEN; ++i)
printf("%c", nwkskey[i]);
printf("\n");
return(EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment