anthonykirby / lora-packet Goto Github PK
View Code? Open in Web Editor NEWLoRa radio packet decoder
License: MIT License
LoRa radio packet decoder
License: MIT License
I noticed that the online decoder is not using the right key for MIC comparison.
If a given packet uses FPort > 0, then the key being used for MIC calculation is the NetSessionKey instead of the AppSessionKey
test data for Rejoin Request should at least be the correct length
hi @anthonykirby, I'm the software architect at TagoIO, the lora-packet is amazing, we would like to use the library on our Payload Parser feature, however, we use typescript types for auto-completion on our front-end (online editor) also the current version is using deprecated API from Node.js as new Buffer(). So, we have rewritten the library to use Typescript and fix it to use new Node.js API (>10.x), also it keeps the same functions, same arguments, totally compatible, so I would like to know if you have the interest to merge both projects to avoid unnecessary fragmentation.
Thanks.
Hi,
I'm trying to use the library with a node ESM package.
I'm sure that I'm missing something, but I cannot make lora-packet work with ESM and TypeScript.
Could it be possible to create an ESM release of lora-packet ?
I wrote a script that logs out packets as they are received from the sensors. Data messages work without issue, however when it tries to read in a Join Accept
it will throw an error when stringify is attempted.
var loraPacket = require('lora-packet');
let payload;
payload = "MIAAAA==";
// payload = "QPF9vkkAAgABlUN4disR/w0="; // base64 equivalent to 40F17DBE4900020001954378762B11FF0D used on the npm example
let bytes = Buffer.from(payload, "base64");
let packet = loraPacket.fromWire(bytes);
console.log(packet.toString());
If you uncomment the second payload, .toString()
will work without issue.
This occurs on every join accept received, currently I am simply ignoring the output of these message types but it would be extremely helpful if this data could be logged in this format.
Hi @anthonykirby ,
I really need your help.
I've subscribed to lora mqtt topic from node and get the json.
{"devEUI":"0102030405060708","fPort":1,"gatewayCount":1,"rssi":-74,"data":"APyLyjXKDQ=="}
I already have appSKey and nwkSKey.
But I don't know how to use your library to decrypt the data.
In your documentation, you wrote this
// decode a packet
var packet = lora_packet.fromWire(new Buffer('40F17DBE4900020001954378762B11FF0D', 'hex'));
Is the string in Buffer construction should be replaced with data from my JSON?
I really appreciate your help.
Thanks
Like the issue#25, I did another comparison between LW 1.0.1 final and the 1.0.2 final version:
https://www.draftable.com/compare/xbpYDtNRPAPH
Here are the main differences :
It's not a big deal to be 1.0.2 compliant and I can help you to do it
Hello,
I am working on an device which use lora.
I tried to parse the following frame :
Message Type = Data
PHYPayload = 6049270226BA00000340020071033500FF0101867B63F7834E04CAC51E59
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 60
MACPayload = 49270226BA00000340020071033500FF0101867B63F7834E04
MIC = CAC51E59
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = 49270226BA00000340020071033500FF01
FPort = 01
FRMPayload = 867B63F7834E04
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 26022749 (Big Endian)
FCtrl = BA
FCnt = 0000 (Big Endian)
FOpts = 0340020071033500FF01
Message Type = Unconfirmed Data Down
Direction = down
FCnt = 0
FCtrl.ACK = true
FCtrl.ADR = true
It seems that the field FPending in FCtrl is missing.
Could you help on that?
Regards,
Error (lora-packet verify): expecting pktBufs packet.MIC to be a Buffer length=4
I can send you the packet and keys if you want. It was a 28 byte payload that should have had GPS readings. A friend has just put up a LoraWAN gateway, and was receiving my packets but I wasn't getting data from TTN, so I copied and pasted from his screen into your simulator to see if it decoded.
Hi,
I have a MAC payload "0307" which is normaly a "UnconfirmedDataUp". But the decoding function return a Mtype = Join Request.
Any idea please ?
Thx
As I can see on the README.md, the current implementation is based on LoRaWAN 1.0.1 draft 3.
I did first a quick comparison between LW 1.0.1 draft 3 and the final version:
https://www.draftable.com/compare/aywIsYazscsj
Here are the main differences (very few):
By checking quickly the difference it will be possible to say that the lora-packet module is LW 1.0.1 compliant
toString() for a Rejoin Request should display something
Hi,
the lora-packet is raising a DeprecationWarning, as shown in following the image
This is due to the node-aes-cmac lib that uses the deprecated Buffer constructor. There is a PR in the original repo fixing this, but was completely ignored. The last update was 7 years ago.
One possible solution is to use aes-cmac. This is a typescript implementation of node-aes-cmac.
incorrect offset for RJCount1
Could i use this library as a service? Essentially, i would like to send the phy payload that my mqtt broker receives from my gateway to the cloud. Then i would like to make requests to the service with the phy payload as input and then it could return me as json format the output with the decoded and decrypted lora packet information.Is is feasible?
Till 65535, decryption of data is perfect, but after rollover, MIC packet matched, but decryption goes wrong, I think it is due to not taking fcnt as 32bit after rollover (i.e. if after rollover value of FCNT is 10, then 65545, value of FCNT should take for decryption.
Thank You
Would be convenient if there was also a getFOpts call that returned MAC commands where present
Could be fine to decode beacon frames 😄
See LoRaWAN Specification, Chapter 15: Beaconing (Class B option)
Showing error while installing lora decoder using npm
Line 357 in 054cc72
A check to see if FCnt exists should be added to the function. If FCnt does not exist, just return null.
Found a typo: https://github.com/anthonykirby/lora-packet/blob/master/lib/packet.js#L615
Should be:
return (that._packet.DLSettings.readUInt8(0) & constants.DLSETTINGS_RXTWODATARATE_MASK) >> constants.DLSETTINGS_RXTWODATARATE_POS;
i.e. POS
and not MASK
.
Hi Anthony,
I find your work on LoRa packet decoding quite intersting. I am currently exploring LoRAWAN with TTN.
I have hard time decoding these payloads.
My data is: 7B226D656173757265496473223A5B315D2C2276616C756573223A5B32325D2C2270726F66696C654964223A313030327D
to me this looks like a HEX string.
I am following the same example you have provided in this GitHUB. How ever when I use the nwSKey and AppSKey, I am not able to see my payload decoded.
The MIC check fails. Is there a way to cross check the decoding process ?
any help is appreciated
Dom
Hello!
I've got the following :
lora-packet-decode --appkey 176C3C601A5FEE50F26FA6D1D193D611 --nwkkey 4A43B74FE531126056CDE739EC05C92B --base64 QNmZCyYAMFwFAVh1pho=
Which yields :
decoding from Base64: QNmZCyYAMFwFAVh1pho=
Decoded packet
--------------
Message Type = Data
PHYPayload = 40D9990B2600305C05015875A61A
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 40
MACPayload = D9990B2600305C0501
MIC = 5875A61A (BAD != CF0C43F5)
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = D9990B2600305C
FPort = 05
FRMPayload = 01
Plaintext = CC ('.')
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 260B99D9 (Big Endian)
FCtrl = 00
FCnt = 5C30 (Big Endian)
FOpts =
Message Type = Unconfirmed Data Up
Direction = up
FCnt = 23600
FCtrl.ACK = false
FCtrl.ADR = false
FCtrl.ADRACKReq = false
But I know the key and transmission to be good. I also have checked on that website :
https://lorawan-packet-decoder-0ta6puiniaut.runkit.sh/?data=QNmZCyYAMFwFAVh1pho%3D&nwkskey=4A43B74FE531126056CDE739EC05C92B&appskey=176C3C601A5FEE50F26FA6D1D193D611
Which seems to use your tool ... but which gave me :
Assuming base64-encoded packet
QNmZCyYAMFwFAVh1pho=
Message Type = Data
PHYPayload = 40D9990B2600305C05015875A61A
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 40
MACPayload = D9990B2600305C0501
MIC = 5875A61A (from packet)
= 5875A61A (expected, assuming 32 bits frame counter with MSB 0001)
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = D9990B2600305C
FPort = 05
FRMPayload = 01 (from packet, encrypted)
= CC (decrypted)
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 260B99D9 (Big Endian)
FCtrl = 00
FCnt = 5C30 (Big Endian)
FOpts =
Message Type = Unconfirmed Data Up
Direction = up
FCnt = 23600 (from packet, 16 bits)
= 89136 (32 bits, assuming MSB 0x0001)
FCtrl.ACK = false
FCtrl.ADR = false
Happy to help if I can answer any question
Just did a fresh Node lts install ... and installed your tool using npm. (so should be pretty much last version)
Is there also a terminal command to take the framepayload as input and the AppSKey and return the decrypted output?
Hello Anthony,
And first of all, things for this library, it's great! :)
I'm trying to use it with Node-Red do do a minimal LoRaWAN server, and I'm trying to send a downlink packet to respond to a "Confirmed Data Up".
This kind of response does not require a FRMPayload, and so does not require a FPort.
But I can't find the way to specify such a packet to the fromFields() function.
When I set the 'payload' field empty, I still get the FPort set. Can we avoid it?
My code is like:
var constructedPacket = lora_packet.fromFields(
{
payload:'',
MType: 'Unconfirmed Data Down',
DevAddr: new Buffer('11223344', 'hex'),
FCtrl: {
ADR: false, // default = false
ACK: true, // default = false
ADRACKReq: false, // default = false
FPending: false // default = false
},
FCnt: new Buffer('0000', 'hex'), // can supply a buffer or a number
},
null,
new Buffer("2B7E151628AED2A6ABF7158809CF4F3C", 'hex') // NwkSKey
);
And I get the frame:
YK8BzAAgAAABmjJuDQ==
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = AF01CC00200000
FPort = 01
FRMPayload =
It's not really critical, but we could avoid this extra-byte for FPort. Is that possible?
Thanks a lot
YoLink provides a range of smart home sensors that communicate with the hub over LoRa. I sniffed few LoRa packets off the temperature and humidity sensor.
I used the following components to do this...
I had to make the following changes to the grc files...
Here are few packets I sniffed every time I pressed the button on the sensor...
26 31 d0 80 9e c1 05 0b 00 44 01 01 d2 17 b9 d1 f3 05 ee 1c 41 73 14 c4 6b b8 61 cf 7e 76 01 b3 94 7f 39 25 34 e2 ad 12 cc 83 d2 (DAska~v9%4)
26 31 d0 80 9e c1 05 0b 00 45 01 01 7d f3 2b 99 60 9e f7 4d 05 aa 99 56 2d 8a f6 2f 3d a2 b0 03 fd 5c 53 64 fb d3 f9 3b bd c0 38 (E}+`MV-/=\Sd;8)
26 31 d0 80 9e c1 05 0b 00 46 01 01 39 7f 17 e6 22 60 80 ac 77 76 fe 4a 0c 6c ac ab 73 a0 6b d2 9c 9b 84 e5 2d ae 67 62 74 ce 07 (F9"`wvJlsk-gbt)
26 31 d0 80 9e c1 05 0b 00 47 01 01 4b 82 db fb 7e f7 4a 70 43 10 93 ae 14 16 49 45 c5 0b 78 37 3d 5d ff d1 a8 13 cd cf 58 98 12 (GK~JpCIEx7=]X)
26 31 d0 80 9e c1 05 0b 00 48 01 01 dc c1 b5 38 8c 1f 78 7d bf c6 51 56 c0 eb e8 bd 6d 6b 8b 82 ed cf 3b c9 30 f2 84 08 78 6b dc (H8x}QVmk;0xk)
26 31 d0 80 9e c1 05 0b 00 49 01 01 b6 a9 f3 e5 09 70 7c 00 a3 bf de b2 30 3e 7e 09 8b 25 49 7e 25 64 75 76 23 7d b4 e0 f1 14 1e (Ip|0>~%I~%duv#})
26 31 d0 80 9e c1 05 0b 00 4a 01 01 60 8d 48 34 ce c6 52 05 ee 55 c0 ea 16 a0 a5 eb 09 c4 60 a2 1b 88 4c d1 e3 fc 17 72 47 1b 6c (J`H4RU`LrGl)
Lines 50 to 52 in 054cc72
Join request messages should have a direction of up. Join accept messages should have a direction of down.
Hi Anthony, nice work building this node module!
I have some nodes that have been sending data for quite a while now. If I parse the raw data (using the correct NwkSKey / AppSKey I do not get the result I expect: e.g.:
Message Type = Data
PHYPayload = 40232E012600711C06BE41598238
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 40
MACPayload = 232E012600711C06BE
MIC = 41598238
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = 232E012600711C
FPort = 06
FRMPayload = BE
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 26012E23 (Big Endian)
FCtrl = 00
FCnt = 1C71 (Big Endian)
FOpts =
Message Type = Unconfirmed Data Up
Direction = up
FCnt = 7281
FCtrl.ACK = false
FCtrl.ADR = false
All of the above is correct.
Of course, you are parsing the encrypted data exactly as per spec so that is not the problem, the thing is however that my FCnt has already rotated past 0xFFFF. So actually for the given message the FCnt that was used by the node to encrypt the message was 0x11C71 (notice the extra 0x1 in front, instead of 0x1C71). The fact that over the air only 2 FCnt bytes are sent means that there is an extra burden on the receiving side to remember the actual FCnt for each particular node.
This causes the 'decrypt' to fail; if I put in the correct higher two bytes in lib/crypt.js:88
87 util.reverse(packet.getBuffers().FCnt),
88 util.bufferFromUInt16LE(0x01), // upper 2 bytes of FCnt (zeroes, sometimes higher ;-) )
the decryption results in the data I expect.
Still investigating the best approach for a solution, if I find one I'll create a PR for you to review
Hi,
I am new to LoRaWAN. I have a lora packet, where I have to provide the Nwskey and Appskey for the tool to decrypt my data. Could any one help me locate the Appskey and Nwskey of the communication. Where can i find the same in my gateway/application?
Your support is required!
Thanks.
excuse me, I have a join accept packet's PHY paylod from ttn webpage, I want to decode and decrypt it, what should I do??
Hello,
I've installed lora-packet on Ubuntu 2204
npm -v
9.2.0
node -v
v19.3.0
npm install --no-fund lora-packet
up to date, audited 19 packages in 2s
when i try to run command-line packet decoding
e.g.
~$lora-packet-decode --hex 40F17DBE4900020001954378762B11FF0D
~$lora-packet-decode: command not found
what am I doing wrong?
When I try to decrypt join accept message, it is giving error in crypto.js Line 131
var packet = lora_packet.fromWire(new Buffer('20425f1c2efd7e1079e704298cfec4814be1f18c6c8b9babd632ea2dfc3eb6242b', 'hex'));
appKey = new Buffer("2b7e151628aed2a6abf7158809cf4f3c", 'hex');
console.log("packet.toString()=\n" + packet);
var DecryptedPacket = lora_packet.decryptJoinAccept(packet, appKey);
console.log("packet.toString()=\n" + DecryptedPacket);
Line 348 in 054cc72
A check to see if FPort exists should be added to the function. If FPort does not exist, just return null.
Awesome job. In the guise of helping out, below are a few packets we're seeing failures on (we're not the source of these, just sniffing so they could be malformed or non LoRaWAN anyway).
{"tmst":2561278763,"chan":3,"rfch":0,"freq":917.4,"stat":-1,"modu":"LORA","datr":"SF7BW125","codr":"4/8","lsnr":-11.2,"rssi":-103,"size":32,"data":"MxBer9FeBKYocsl/ghlVobdUIPD/zCDPmZNH4YqoojU="}
/usr/local/lib/node_modules/lora-packet/lib/packet.js:707
msg += "DLSettings.RX1DRoffset = " + that.getRxOneDRoffset() + "\n";
^
TypeError: that.getRxOneDRoffset is not a function
at LoraPacket.toString (/usr/local/lib/node_modules/lora-packet/lib/packet.js:707:55)
at Socket.stage0.on (/Users/rob/Documents/repositories/nisient/loragw/gwtest1680.js:44:41)
at emitTwo (events.js:126:13)
at Socket.emit (events.js:214:7)
at UDP.onMessage [as onmessage] (dgram.js:658:8)
{"tmst":101395732,"chan":5,"rfch":1,"freq":917.8,"stat":-1,"modu":"LORA","datr":"SF7BW125","codr":"4/7","lsnr":-11,"rssi":-103,"size":107,"data":"OzXyHlIP87QFJcUUSwJJ05OfMI16FN+11LBIFbx0i3Ml76YDsWE6EXTuVIHcZHq8W9y7YkvXIzD/UjDn90geq+cIc1ESELjmS/3PKQuz2mkh4gaIODijgYsO6y3tgS5pN8GfWnWFfaL6QnM="}
/usr/local/lib/node_modules/lora-packet/lib/packet.js:707
msg += "DLSettings.RX1DRoffset = " + that.getRxOneDRoffset() + "\n";
^
TypeError: that.getRxOneDRoffset is not a function
at LoraPacket.toString (/usr/local/lib/node_modules/lora-packet/lib/packet.js:707:55)
at Socket.stage0.on (/Users/rob/Documents/repositories/nisient/loragw/gwtest1680.js:45:42)
at emitTwo (events.js:126:13)
at Socket.emit (events.js:214:7)
at UDP.onMessage [as onmessage] (dgram.js:658:8)
{"tmst":1159216707,"chan":4,"rfch":1,"freq":917.6,"stat":-1,"modu":"LORA","datr":"SF7BW125","codr":"4/5","lsnr":-12.5,"rssi":-103,"size":82,"data":"LguOqcAjnlkI3QiAlgbBFu4jHqHM6fkVARZiMz0wkO1LxfR8xzTJ2bC6Zv9geek2gTorqOUIgSLQZKpKvuZGUc9NsbZBegjRKqmzhvS0IfkNQQ=="}
/usr/local/lib/node_modules/lora-packet/lib/packet.js:707
msg += "DLSettings.RX1DRoffset = " + that.getRxOneDRoffset() + "\n";
^
TypeError: that.getRxOneDRoffset is not a function
at LoraPacket.toString (/usr/local/lib/node_modules/lora-packet/lib/packet.js:707:55)
at Socket.stage0.on (/Users/rob/Documents/repositories/nisient/loragw/gwtest1680.js:44:42)
at emitTwo (events.js:126:13)
at Socket.emit (events.js:214:7)
at UDP.onMessage [as onmessage] (dgram.js:658:8)
{"tmst":2889130812,"chan":5,"rfch":1,"freq":917.8,"stat":-1,"modu":"LORA","datr":"SF7BW125","codr":"OFF","lsnr":-8.8,"rssi":-102,"size":6,"data":"mp6cIKwk"}
buffer.js:972
throw new RangeError('Index out of range');
^
RangeError: Index out of range
at checkOffset (buffer.js:972:11)
at Buffer.readInt8 (buffer.js:1098:5)
at _initialiseFromWireformat (/usr/local/lib/node_modules/lora-packet/lib/packet.js:166:33)
at LoraPacket._fromWire (/usr/local/lib/node_modules/lora-packet/lib/packet.js:116:13)
at Object.exports.fromWire (/usr/local/lib/node_modules/lora-packet/lib/packet.js:7:8)
at Socket.stage0.on (/Users/rob/Documents/repositories/nisient/loragw/gwtest1680.js:43:26)
at emitTwo (events.js:126:13)
at Socket.emit (events.js:214:7)
at UDP.onMessage [as onmessage] (dgram.js:658:8)
{"tmst":2039534628,"chan":6,"rfch":1,"freq":918,"stat":-1,"modu":"LORA","datr":"SF7BW125","codr":"4/6","lsnr":-12,"rssi":-102,"size":230,"data":"L6B+BD7/WzsJh+uNIHwKa3rV1/kP63fYQhYwXpAQWoDdsPu6iSOL9DPaC8HsKpMaFHc96wcLX5fh5SCd+mO5AoGdagie9Cdxz4bJo52R5hwDbWTXeOta0CXv+GM1vP5sBsD2hCF6NterPz3QeC7/8VvN7hfohVdkWneAa2r6JhXwFisPbh4V2Bfxrvn1k7Prc4BMVHdzt7WpTVVUUvckypPo52K1L5bl0pd1C5XD6ULNzmUSs9y9vdGsNow3PM8HScxLDvUgm9ENuooeTiEh9zmIxLSFp2OHIV0bf7TmCw4e8EPF/pE="}
/usr/local/lib/node_modules/lora-packet/lib/packet.js:707
msg += "DLSettings.RX1DRoffset = " + that.getRxOneDRoffset() + "\n";
^
TypeError: that.getRxOneDRoffset is not a function
at LoraPacket.toString (/usr/local/lib/node_modules/lora-packet/lib/packet.js:707:55)
at Socket.stage0.on (/Users/rob/Documents/repositories/nisient/loragw/gwtest1680.js:44:42)
at emitTwo (events.js:126:13)
at Socket.emit (events.js:214:7)
at UDP.onMessage [as onmessage] (dgram.js:658:8)
I have tried decrypting a payload. In this process, the decoding is successful, MIC Check came to be "OK".
packet MIC and calculated MIC came out to be identical.
But the Decrypted messages shows random values like �!\u0000 or \t etc.
Here is the sample data that I have used for decryption.
Payload: 402B19012600040001B2E2E4F81F44B6
NetworkSKey: EA68299F93F4AB9886D36755E7E23FC3
AppSKey: 57D69E5DE46FEAF8B5FBF6CC1F436B58
Output:
"packet.toString()=\nMessage Type = …CK = false\n FCtrl.ADR = false\n"
packet.toString()=
Message Type = Data
PHYPayload = 402B19012600040001B2E2E4F81F44B6
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 40
MACPayload = 2B19012600040001B2E2E4
MIC = F81F44B6
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = 2B190126000400
FPort = 01
FRMPayload = B2E2E4
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 2601192B (Big Endian)
FCtrl = 00
FCnt = 0004 (Big Endian)
FOpts =
Message Type = Unconfirmed Data Up
Direction = up
FCnt = 4
FCtrl.ACK = false
FCtrl.ADR = false
"packet MIC=f81f44b6"
"FRMPayload=b2e2e4"
"MIC check=OK"
"calculated MIC=f81f44b6"
"Decrypted='�!\u0000'"
The actual data sent from the node is a number - "222555".
Tried on npm Runkit: https://npm.runkit.com/lora-packet
Mostly changes to the join process but be good to detect
Hello,
First of all I'm glad that I found your project. My research shows that everybody is just going the easy way using the thingsnetwork but I see no point in my case. I would like to receive data from my weather station and occasionally send some commands to it, I don't want to be limited to any like 40 messages per day etc.
I would like to setup an own private lora gateway which decrypts packet just for my device, ignores everything else and processes the output locally on a raspberry pi, eg data comes in->decode->write to text file.
Thank you
It would be nice to make this work in a regular browser.
Hi,
The Digital Matters Oyster node sends packets like this:
800E21062602900AE4AE010FCD776DB3DF96F4CB75656695F9CC
However, lora-packet always says the MIC is wrong.
$ node_modules/lora-packet/bin/lora-packet-decode --appkey E144C6ACB81F17F05CFEB90EF55D615C --nwkkey 448B20D2E0ED62F3DC61ADE7B589B65A --hex $trimmed_line
decoding from Hex: 800e21062602900ae4ae010fcd776db3df96f4cb75656695f9cc
Decoded packet
--------------
Message Type = Data
PHYPayload = 800E21062602900AE4AE010FCD776DB3DF96F4CB75656695F9CC
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 80
MACPayload = 0E21062602900AE4AE010FCD776DB3DF96F4CB7565
MIC = 6695F9CC (BAD != F9CC34D1)
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = 0E21062602900AE4AE
FPort = 01
FRMPayload = 0FCD776DB3DF96F4CB7565
Plaintext = E5F33FEDA757FB5A6900A5 ('..?..W.Zi..')
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 2606210E (Big Endian)
FCtrl = 02
FCnt = 0A90 (Big Endian)
FOpts = E4AE
Message Type = Confirmed Data Up
Direction = up
FCnt = 2704
FCtrl.ACK = false
FCtrl.ADR = false
`
I'm pretty confident in those keys because the FRMPayload plaintext is correct (it's an actual, accurate, GPS packet).
Let me know if I can provide anything else to help.
I have the Nexus Demoboard from ideetron which sends some temperature and humidity measures at a specific logic for the Things Network and the Cayenne Dashboard.
If i choose to buy customed temperature/humidity sensors , they will send a payload at a different logic and they cannot be configured.
Do you think that i have to use the same sensors for my app in order to receive the same type of payload at the uplink?
I've double checked all the nwk and appkey to be correct, and confirmed that the data works fine int he ttn device data console. When I try to use the module through node red, the msg.payload.out if emnty.
when I tried the CLI for lora_packet I get the same blank payload returned.
./node_modules/lora-packet/bin/lora-packet-decode --appkey "7679A920DC79C0DECC693E34E670B11F" --nwkkey "4BBA414130E0A0C87FE0A7EAA257E9BD" --base64 "YGcXASaKCwADQAIAcQM1AP8BbePzEg=="
Message Type = Data
PHYPayload = 60671701268A0B000340020071033500FF016DE3F312
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 60
MACPayload = 671701268A0B000340020071033500FF01
MIC = 6DE3F312 (OK)
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = 671701268A0B000340020071033500FF01
FPort =
FRMPayload =
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 26011767 (Big Endian)
FCtrl = 8A
FCnt = 000B (Big Endian)
FOpts = 0340020071033500FF01
Message Type = Unconfirmed Data Down
Direction = down
FCnt = 11
FCtrl.ACK = false
FCtrl.ADR = true
in the ttn console the data is on port 1, (but port in outpue is "")
this should return the byte array of be9e524781aa01070f2a
lora-packet shows incorrect details for a Join Accept:
Without first decrypting the message, the following lines in _initialiseFromWireformat
are not quite valid:
Lines 138 to 149 in 53190fa
I guess toString
should only print the message type, without any of the erroneous details:
Lines 408 to 414 in 53190fa
For a not-encrypted Join Request like 00DC0000D07ED5B3701E6FEDF57CEEAF0085CC587FE913
lora-packet correctly shows:
Message Type = Join Request
AppEUI = 70B3D57ED00000DC
DevEUI = 00AFEE7CF5ED6F1E
DevNonce = CC85
MIC = 587FE913
For a matching response, 204DD85AE608B87FC4889970B7D2042C9E72959B0057AED6094B16003DF12DE145
, it currently erroneously suggests:
Message Type = Join Accept
AppNonce = 5AD84D
NetID = B808E6
DevAddr = 9988C47F
MIC = F12DE145
This is wrong as the Join Accept payload (including its MIC) is encrypted using the secret AppKey (not to be confused with the session AppSKey, which is actually derived from the Join Accept). When decrypted using AppKey B6B53F4A168A7A88BDF7EA135CE9CFCA
, the above Join Accept would yield:
AppNonce = E5063A
NetID = 000013
DevAddr = 26012E43
DLSettings = 03
RXDelay = 01
CFList = 184F84E85684B85E84886684586E8400
= decimal 8671000, 8673000, 8675000, 8677000, 8679000
MIC = 55121DE0
(The Things Network has been assigned a 7-bits "device address prefix" a.k.a. NwkID %0010011
. Using that, TTN currently sends NetID 0x000013
, and a TTN DevAddr always starts with 0x26
or 0x27
.)
When the DevNonce from the Join Request is known as well, then the session keys can be derived:
NwkSKey = 2C96F7028184BB0BE8AA49275290D4FC
AppSKey = F3A5C8F0232A38C144029C165865802C
The following working example can also be seen at https://runkit.com/avbentem/deciphering-a-lorawan-otaa-join-accept
/*
* Shows how to decode a LoRaWAN OTAA Join Accept message, and derive the session keys.
*/
var reverse = require('buffer-reverse');
'use strict';
var CryptoJS = require('crypto-js');
var aesCmac = require('node-aes-cmac').aesCmac;
// Secret AppKey as programmed in the device
var appKey = Buffer.from('B6B53F4A168A7A88BDF7EA135CE9CFCA', 'hex');
// DevNonce as generated in Join Request
var devNonce = Buffer.from('CC85', 'hex');
// Full packet: 0x20 MHDR, Join Accept (12 bytes, 16 bytes optional CFList, 4 bytes MIC)
var phyPayload = Buffer.from(
'204dd85ae608b87fc4889970b7d2042c9e72959b0057aed6094b16003df12de145', 'hex');
// Initialization vector is always zero
var LORA_IV = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
// Encrypts the given buffer, returning another buffer.
function encrypt(buffer, key) {
var ciphertext = CryptoJS.AES.encrypt(
CryptoJS.lib.WordArray.create(buffer),
CryptoJS.lib.WordArray.create(key),
{
mode: CryptoJS.mode.ECB,
iv: LORA_IV,
padding: CryptoJS.pad.NoPadding
}
).ciphertext.toString(CryptoJS.enc.Hex);
return new Buffer(ciphertext, 'hex');
}
// ## Decrypt payload, including MIC
//
// The network server uses an AES decrypt operation in ECB mode to encrypt the join-accept
// message so that the end-device can use an AES encrypt operation to decrypt the message.
// This way an end-device only has to implement AES encrypt but not AES decrypt.
var mhdr = phyPayload.slice(0, 1);
var joinAccept = encrypt(phyPayload.slice(1), appKey);
// ## Decode fields
//
// Size (bytes): 3 3 4 1 1 (16) Optional 4
// Join Accept: AppNonce NetID DevAddr DLSettings RxDelay CFList MIC
var i = 0;
var appNonce = joinAccept.slice(i, i += 3);
var netID = joinAccept.slice(i, i += 3);
var devAddr = joinAccept.slice(i, i += 4);
var dlSettings = joinAccept.slice(i, i += 1);
var rxDelay = joinAccept.slice(i, i += 1);
if (i + 4 < joinAccept.length) {
// We need the complete little-endian list (including its RFU byte) for the MIC
var cfList = joinAccept.slice(i, i += 16);
// Decode the 5 additional channel frequencies
var frequencies = [];
for (var c = 0; c < 5; c++) {
frequencies.push(cfList.readUIntLE(3 * c, 3));
}
var rfu = cfList.slice(15, 15 + 1);
}
var mic = joinAccept.slice(i, i += 4);
// ## Validate MIC
//
// Below, the AppNonce, NetID and all should be added in little-endian format.
// cmac = aes128_cmac(AppKey, MHDR|AppNonce|NetID|DevAddr|DLSettings|RxDelay|CFList)
// MIC = cmac[0..3]
var micVerify = aesCmac(
appKey,
Buffer.concat([
mhdr,
appNonce,
netID,
devAddr,
dlSettings,
rxDelay,
cfList
]),
{returnAsBuffer: true}
).slice(0, 4);
// ## Derive session keys
//
// NwkSKey = aes128_encrypt(AppKey, 0x01|AppNonce|NetID|DevNonce|pad16)
// AppSKey = aes128_encrypt(AppKey, 0x02|AppNonce|NetID|DevNonce|pad16)
var sKey = Buffer.concat([
appNonce,
netID,
reverse(devNonce),
Buffer.from('00000000000000', 'hex')
]);
var nwkSKey = encrypt(Buffer.concat([Buffer.from('01', 'hex'), sKey]), appKey);
var appSKey = encrypt(Buffer.concat([Buffer.from('02', 'hex'), sKey]), appKey);
var r = ' Payload = ' + phyPayload.toString('hex')
+ '\n MHDR = ' + mhdr.toString('hex')
+ '\n Join Accept = ' + joinAccept.toString('hex')
+ '\n AppNonce = ' + (reverse(appNonce)).toString('hex')
+ '\n NetID = ' + (reverse(netID)).toString('hex')
+ '\n DevAddr = ' + (reverse(devAddr)).toString('hex')
+ '\n DLSettings = ' + dlSettings.toString('hex')
+ '\n RXDelay = ' + rxDelay.toString('hex')
+ '\n CFList = ' + cfList.toString('hex')
+ '\n = decimal ' + frequencies.join(', ')
+ '\n message MIC = ' + mic.toString('hex')
+ '\nverified MIC = ' + micVerify.toString('hex')
+ '\n NwkSKey = ' + nwkSKey.toString('hex')
+ '\n AppSKey = ' + appSKey.toString('hex');
console.log('<pre>\n' + r + '\n</pre>');
Hello, i'm trying to use lora-packet-decode to decode payload :
lora-packet-decode --nwkkey 95AC484C0B6CA199F80311CADAA774C1 --appkey F5D893278F7E3F23C3DAB5A19AE0CD6C --base64 QPjyCyaAhAEKxgot72bu6AZmyLrY
and i obtain :
( PHYPayload = MHDR[1] | MACPayload[..] | MIC[4] )
MHDR = 40
MACPayload = F8F20B268084010AC60A2DEF66EEE806
MIC = 66C8BAD8 (BAD != 83269847)
( MACPayload = FHDR | FPort | FRMPayload )
FHDR = F8F20B26808401
FPort = 0A
FRMPayload = C60A2DEF66EEE806
Plaintext = 7665F6EBEE99543D ('ve....T=')
( FHDR = DevAddr[4] | FCtrl[1] | FCnt[2] | FOpts[0..15] )
DevAddr = 260BF2F8 (Big Endian)
FCtrl = 80
FCnt = 0184 (Big Endian)
FOpts =
Message Type = Unconfirmed Data Up
Direction = up
FCnt = 388
FCtrl.ACK = false
FCtrl.ADR = true
FCtrl.ADRACKReq = false
Where it seems there is a problem concerning MIC. Is this problem come from the use of LoRaWAN version 1.1 or other ?
Thanks
Eric
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.