Commit 02280194 authored by Guillaume Gonnet's avatar Guillaume Gonnet
Browse files

Add a Node.js script for decoding join accept messages.

parent efda2080
/*
This file decodes a JOIN message sent on port 10.
Usage: node decode-join.js <app key> <payload>
Example: node decode-join.js \
4b20ef23b1c3a9393f034f6527ca71f2 \
1C386337ccbbaae7cd2c010000184F84E85684B85E84886684586E8400AB7800
The format of the payload is the following:
<join size> <join accept + cf list> <padding> <dev nonce> <zero>
--- 1B ---- ------ 12B to 28B ----- --------- --- 2B ---- - 1B -
The payload have exaclty 32 bytes.
Copyright (C) 2019, ENSIMAG students
This project is under the MIT license
*/
const crypto = require("crypto");
// Parse command line.
const args = process.argv.splice(2);
if (args.length != 2) {
console.error("Usage: node decode-join.js <app key> <payload>");
process.exit(1);
}
// Validate input data.
const appkey = Buffer.from(args[0], "hex");
const payload = Buffer.from(args[1], "hex");
if (appkey.length != 16) {
console.error("AppKey must have exaclty 16 bytes.");
process.exit(1);
}
if (payload.length != 32) {
console.error("Input payload must have at least 32 bytes.");
process.exit(1);
}
// Extract payload size.
const PayloadSize = payload.readUInt8(0);
// Extract DevNonce.
const DevNonce = payload.readUInt16LE(29);
// Prepare nonce for extrating NwkSKey and AppSKey.
const nonce = Buffer.alloc(16);
payload.copy(nonce, 1, 1, 7);
nonce.writeUInt16LE(DevNonce, 7);
// Extact NwkSKey (using AES).
let cipher = crypto.createCipheriv("AES-128-CBC", appkey, Buffer.alloc(16));
nonce.writeUInt8(0x01, 0);
const NwkSKey = cipher.update(nonce);
// Extact NwkSKey (using AES).
cipher = crypto.createCipheriv("AES-128-CBC", appkey, Buffer.alloc(16));
nonce.writeUInt8(0x02, 0);
const AppSKey = cipher.update(nonce);
// Extract NetID.
const NetID = payload.readUInt32LE(4) & 0xFFFFFF;
// Extract DevAddr.
const DevAddr = payload.readUInt32LE(7);
// Extract DLSettings.
const Rx1DrOffset = (payload.readUInt8(11) >> 4) & 0x07;
const Rx2ChannelDr = (payload.readUInt8(11) >> 0) & 0x0F;
// Extract ReceiveDelay1.
const ReceiveDelay1 = payload.readUInt8(12) & 0x0F;
// Extract CF list.
const CFList = [];
if (PayloadSize == 28) {
for (let i = 0; i < 5; i++)
CFList.push(payload.readUInt32LE(13 + 3*i) & 0xFFFFFF);
}
else if (PayloadSize > 12) {
console.warn("Payload size is invalid: %d", PayloadSize);
}
// Convert a number to hex with a fixed number of characters.
Number.prototype.toFixHex = function(len) {
return ("0".repeat(len) + this.toString(16)).substr(-len);
};
// Log extracted parameters.
console.log("\n" + `
Network parameters:
NwkSKey = ${NwkSKey.toString("hex").toUpperCase()}
AppSKey = ${AppSKey.toString("hex").toUpperCase()}
NetID = ${NetID.toFixHex(6).toUpperCase()}
DevAddr = ${DevAddr.toFixHex(8).toUpperCase()}
LoRa settings:
Rx1DrOffset = ${Rx1DrOffset}
Rx2ChannelDr = ${Rx2ChannelDr}
ReceiveDelay1 = ${ReceiveDelay1}
CFList:
${(CFList.length == 0) ?
"no frenquencies defined" : CFList.join(", ") }
`.trim() + "\n");
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment