Implement an extra layer of encryption, but it's untested.

master
Starbeamrainbowlabs 4 years ago
parent 0604062966
commit 723941bdf8
  1. 6
      README.md
  2. 11
      iot/main/settings.custom.cpp.example
  3. 7
      iot/main/settings.custom.h
  4. 6
      iot/main/transmission.cpp
  5. 4
      server/settings.default.toml
  6. 10
      server/ttn-app-server/DecodePayload.mjs
  7. 7
      server/ttn-app-server/MessageHandler.mjs

@ -20,8 +20,14 @@ Run `bash ./build setup` from the command line at the root of this repository.
### IoT Device
- Copy `settings.custom.cpp.example` to `settings.custom.cpp` and fill in the fields there
- This Bash one-liner can be used to generate a new encryption key in the right formats: `head -c16 /dev/urandom | od -tx1 | awk '{ gsub(/^0+\s+/, "", $0); toml=$0; gsub(/\s+/, "", toml); print("settings.toml format: " toml); arduino=toupper($0); gsub(/\s+/, ", 0x", arduino); print("settings.custom.cpp format: 0x" arduino); exit }'`
- Review `settings.h` to make sure it matches your setup
- Copy the folders in `iot/libraries` to your Arduino IDE libraries folder
### Server
- The `bash ./build setup` should have already installed the necessary dependencies.
- Create `settings.toml` in the root of the repository if it doesn't exist already.
- Review `server/settings.default.toml` and adjust `settings.toml` to fill in the values for the required fields, not forgetting the encryption key generated when setting up the IoT device.
## Useful Links
- Entropy extraction from the watchdog timer vs the internal clock: https://github.com/taoyuan/Entropy

@ -8,19 +8,24 @@
// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const PROGMEM u1_t NWKSKEY[16] = { .... };
const PROGMEM u1_t NWKSKEY[16] = { .... };
// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const u1_t PROGMEM APPSKEY[16] = { ..... };
const u1_t PROGMEM APPSKEY[16] = { ..... };
// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = 0x....; // <-- Change this address for every node!
const u4_t DEVADDR = 0x....; // <-- Change this address for every node!
// The RFM95 pin mapping
const lmic_pinmap lmic_pins = {
.nss = PIN_SPI_CS_RFM95,
.rxtx = LMIC_UNUSED_PIN,
.rst = 9,
.dio = {2, 6, 7},
};
// The AES-ECB 128-bit key to encrypt the data with.
// See the README for a Bash oneliner that generates a new key in the right format.
uint8_t encrypt_key[16] = { ..... };

@ -7,8 +7,15 @@
* it settings.cpp, and edit that instead.
*/
// The network session key. From The Things Network console
extern const PROGMEM u1_t NWKSKEY[16];
// The application session key from The Things Network console
extern const u1_t PROGMEM APPSKEY[16];
// The device address
extern const u4_t DEVADDR;
// The pin mapping for the RFM95
extern const lmic_pinmap lmic_pins;
// The key to encrypt the data with
extern uint8_t encrypt_key[16];

@ -8,6 +8,9 @@
// Global static variable that's used to detect when LMIC has finished doing it's thing
bool is_sending_complete = false;
// Defined as part of LMIC, but LMIC is compiled and linked in separately
extern "C" void lmic_aes_encrypt(unsigned char *Data, unsigned char *Key);
void transmit_counter_save() {
store_eeprom_uint32_save(0, LMIC.seqnoUp);
@ -82,6 +85,9 @@ void transmit_init() {
* @param length The length of the given message.
*/
bool transmit_send(uint8_t* data, int length) {
// Encrypt the data with the extra encryption key
lmic_aes_encrypt(data, encrypt_key);
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
// Serial.println(F("OP_TXRXPEND: Job running, can't send"));

@ -40,6 +40,10 @@ app_id = "CHANGE_THIS"
# there.
access_key = "CHANGE_THIS"
# The additional encryption key, in hex, generated when setting up the IoT device.
# This is used as an exrtra layer of encryption to ensure that The Things Network does not have access to the decrypted data.
encryption_key = "CHANGE_THIS"
# A list of devices to monitor.
# If a device isn't specified here, then we won't hear messages from it.
# FUTURE: Automatically fetch a list of devices from the TTN API

@ -1,11 +1,17 @@
"use strict";
import aes from 'aes-js';
const offset_id = 0;
const offset_lat = 32 / 8;
const offset_lng = (32 / 8) + (32 / 8);
function decode_payload(payload_base64) {
let payload_buffer = Buffer.from(payload_base64, "base64");
function decode_payload(payload_base64, key_hex) {
let payload_buffer_enc = Buffer.from(payload_base64, "base64");
let key_buffer = Buffer.from(key_hex, "hex");
let aes_ecb = new aes.ModeOfOperation.ecb(key_buffer);
let payload_buffer = aes_ecb.decrypt(payload_buffer_enc);
// console.debug(`Offsets: ${offset_id}, ${offset_lat}, ${offset_lng}`);
// console.debug(`Message hex: ${payload_buffer.toString("hex")}`)

@ -16,7 +16,12 @@ class MessageHandler {
async handle(message) {
if(this.debug) console.log(message);
let decoded_payload = decode_payload(message.payload_raw);
if(this.settings.ttn.encryption_key == "CHANGE_THIS") {
this.log.error(`Error: No encryption key specified. Try filling in the required values in settings.toml. If they don't exist yet, try using server/settings.default.toml as a reference.`);
return false;
}
let decoded_payload = decode_payload(message.payload_raw, this.settings.ttn.encryption_key);
if(this.debug) console.log(decoded_payload);
let rssis = [];

Loading…
Cancel
Save