Verify 16 bits public MIC of LoRaWAN 1.1 uplink

node v14.20.1
version: 1.0.1
endpointsharetweet
/** * Validate the "public" 16 bits of full 32 bits LoRaWAN 1.1 MIC in uplink frame. * * To calculate the other 16 bits, one must also know at which data rate and channel the uplink * was transmitted (and, in case of a downlink confirmation, also the downlink's frame counter), * along with the secret SNwkSIntKey. * * See https://lora-alliance.org/sites/default/files/2018-04/lorawantm_specification_-v1.1.pdf#page=27 * and https://github.com/anthonykirby/lora-packet/issues/29 */ // This throws deprecation warnings; see https://github.com/allan-stewart/node-aes-cmac/pull/2 const aesCmac = require('node-aes-cmac').aesCmac; // Secret FNwkSIntKey as programmed in the device or derived from a 1.1 Join Accept const fNwkSIntKey = Buffer.from('448B20D2E0ED62F3DC61ADE7B589B65A', 'hex'); // Regular 1.1 uplink const phyPayload = Buffer.from('800E21062602900AE4AE010FCD776DB3DF96F4CB75656695F9CC', 'hex'); const devAddr = phyPayload.readUInt32LE(1); // Counter is 32 bits, but only 16 LSB are in the LoRaWAN packet; assume MSB is 0x0000 const fCntUp = phyPayload.readUInt16LE(6); const msgLen = phyPayload.length - 4; const msg = phyPayload.slice(0, msgLen); const mic = phyPayload.slice(msgLen); // See https://lora-alliance.org/sites/default/files/2018-04/lorawantm_specification_-v1.1.pdf#page=27 const b0 = Buffer.allocUnsafe(16); let i = 0; i = b0.writeUInt8(0x49, i); i = b0.writeUInt32LE(0x00000000, i); i = b0.writeUInt8(0x00, i); i = b0.writeUInt32LE(devAddr, i); i = b0.writeUInt32LE(fCntUp, i); i = b0.writeUInt8(0x00, i); i = b0.writeUInt8(msgLen, i); // cmacF = aes128_cmac(FNwkSIntKey, B0 | msg) const cmacFVerify = aesCmac( fNwkSIntKey, Buffer.concat([b0, msg]), {returnAsBuffer: true} ).slice(0, 4); `<pre> Full MIC from packet = ${mic.toString('hex')} Calculated cmacF = ${cmacFVerify.toString('hex')} </pre>`;
Loading…

no comments

    sign in to comment