Uplink and downlink messages signed with SHA tokens

  • 10 August 2016
  • 12 reacties
  • 3012 keer bekeken

Reputatie 2
Badge +1
This post has become obsolete as it was incorporated in the Setting up your Application Server topic.

Both up and downlink messages are signed with a SHA token. SHA256 (Secure Hash Algorithm) is used together with an SHA key to generate a token that can only be generated if you have the corresponding key.

For uplink messages it's up to the Developer to set up verification in the Application Server. For donwlink messages all message must be signed with a valid token.

Receiving and validating uplink messages:
The application server retrieves the query-parameters of an HTTP post and hashes these WITHOUT the Token QP (Query parameters include the AS_ID and the Time):
code:
 query-parameters := LrnDevEui=000000000F1D8693&LrnFPort=2&LrnInfos=UPHTTP_LAB_LORA&AS_ID=app1.sample.com&Time=2016-01-11T14:11:11

From the body of you LoRa message you need some elements which you concatenate without separator: CustomerID, DevEUI, FPort, FCntUp, payload_hex.
code:
body-elements := 100000507000000000F1D8693270110027bd00

Both the KPN servers and your application server should now the secret 128 bits AS Key. You can find the AS-key under your profile
code:
AsKey:= 46ab678cd45df4a4e4b375Eacd096acc

The application server re-computes the token as SHA-256():
code:
token:= SHA 256(100000507000000000F1D8693270110027bd00LrnDevEui=000000000F1D8693&LrnFPort=2&LrnInfos=UPHTTP_LAB_LORA&AS_ID=app1.sample.com&Time=2016-01-11T14:11:1146ab678cd45df4a4e4b375Eacd096acc)

This will result in a hex string that must be the same as the key provided in the token field of the query parameter, so you are sure the sender is valid.
code:
encrypted-token:= 9bf99ba78791ad7f02c8d24dafe0a47da895ded5a0add99584d48d45c0e750a3


Sending downlink messages from the application server
To generate the mandatory token for downlink messages, you should get the query parameters as a string and append the key. Put the resulting key through a SHA-256 function to get your token.
code:

Example query-parameters:= DevEUI=000000000F1D8693&FPort=1&Payload=00&AS_ID=app1.sample.com&Time=2016-01-11T14:28:00

token:= SHA 256(DevEUI=000000000F1D8693&FPort=1&Payload=00&AS_ID=app1.sample.com&Time=2016-01-11T14:28:0046ab678cd45df4a4e4b375Eacd096acc)


Remember that the can be found at you application server in Thingpark or your user profile in the Developer Portal and is 46ab678cd45df4a4e4b375Eacd096acc in this example.

The resulting is encoded as an hex string
code:
Token=b5a84fe9c8921e9de359e3041a37b76c4b122f6f9b83577b5596c842052f7e62


Pro-Tips
  • Please refer to this topic on how to send the signed message.
  • SHA tokens can be case sensitive, our advise is to always use lower case tokens
  • Also the IoT Academy Github contains a step-by-step explanation about how to implement an application server in NodeRed: https://github.com/iotacademy/NodeRed_KPN_LoRa/wiki.

[color=green]

Useful links

[/color]- [color=#094ab1]LoRa:[/color] Starters Guide
- [color=#094ab1]LoRa:[/color] Forum and Manuals
- [color=#094ab1]LoRa:[/color] Geolocation
- [color=#094ab1]LoRa:[/color] Dictionary & Definitions
- [color=green]FAQ:[/color] Frequently Asked Questions
- [color=green]Tools:[/color] www.LoRaTools.nl

12 reacties

Hi,

I've been using a Node-Red sample app from the Marvin/RDM course (https://github.com/iotacademy/NodeRed_KPN_LoRa/wiki/3.-Validating-the-Token). I'm now encountering errors upon verification of the SHA-256 token. It appears that msg.req.query contains unexpected content.

When I debug it it gives me the following content:

NaNLrnDevEui=0059AC00001801E3&LrnFPort=1&LrnInfos=null&AS_ID=EasyLogicBV.developer&Time=2017-02-01T11:05:04.612Z

I presume the NaN (Not a Number) is the thing that screws it up. Has anything changed to cause the NaN to appear, and how do I get rid of it?

Thanks in advance

Peter van Es
Easylogic BV
I've found the problem... apparently the json format for the message in the developer portal has changed to match the json of the Thinkpark portal.

The code in my "Catch Parse Input" needed to be changed to match the detection.
Reputatie 7
Badge +11
Thanks Peter for letting us know and good to hear you've found the cause by yourself. 🙂
Hallo,

Ik krijg het niet voor elkaar om het Token te valideren. Ik doe precies wat in de beschrijving staat. Exact dezelfde variabelen maar hij klopt niet. In zowel het voorbeeld als in Node-RED.

Nu moet ik er wel bij zeggen: Ik kan niet vanaf het internet direct naar mijn webserver sturen. Ik lees het bericht uit met Hookbin. En vervolgens gebruik ik de chrome extensie advanced rest api client om het request na te bootsen.

Ik had tevens ook gezien dat via de portal bij de AS key streepjes tussen de code staat, deze moet ik er zelf handmatig uithalen. Zijn er nog andere weetjes die ik over het hoofd zie?

Hieronder mijn 3 elementen en het JSON request + Query parameters.

code:
Query-parameters = "LrnDevEui=0059AC000018173D&LrnFPort=1&LrnInfos=null&AS_ID=TestingASID&Time=2017-04-26T15:33:50.381+02:00"


code:
Body Elements = "1234567890059AC000018173D23000000"

code:
 AS Key = "1f9f6b77c5fd42618fc702f603dd3e9b"


code:
Token-Encrypted = "307d8d57a205ce792721648d9b3a6ba624804d6833ab0d55da4c79f87b11d92d"

code:
Token-Calculated = "b57d0198d4d4d70f07a11bdca4532342fb9b63cb8323ab121c59280f579af5e3"


JSON Request van de Body:

code:
{
"DevEUI_uplink": {
"Time": "2017-04-26T03:33:50.377+0200",
"DevEUI": "0059AC000018173D",
"FPort": "2",
"FCntUp": "3",
"ADRbit": "1",
"MType": "4",
"FCntDn": "3",
"payload_hex": "000000",
"mic_hex": "5f95a77a",
"Lrcid": "0059AC01",
"LrrRSSI": "-100.000000",
"LrrSNR": "5.750000",
"SpFact": "12",
"SubBand": "G0",
"Channel": "LC7",
"DevLrrCnt": "4",
"Lrrid": "080603DB",
"LrrLAT": "52.069241",
"LrrLON": "4.349416",
"Lrrs": {
"Lrr": [
{
"Lrrid": "080603DB",
"Chain": "0",
"LrrRSSI": "-100.000000",
"LrrSNR": "5.750000",
"LrrESP": "-101.024590"
},
{
"Lrrid": "080E00C8",
"Chain": "0",
"LrrRSSI": "-118.000000",
"LrrSNR": "-4.000000",
"LrrESP": "-123.455406"
},
{
"Lrrid": "080602C9",
"Chain": "0",
"LrrRSSI": "-119.000000",
"LrrSNR": "-9.500000",
"LrrESP": "-128.961838"
}
]
},
"CustomerID": "123456789",
"CustomerData": {
"alr": {
"pro": "SMTC/LoRaMote",
"ver": "1"
}
},
"ModelCfg": "0",
"AppSKey": "a002tnre9d662017ad916032313527d9"
}
}


POST Request Query string :
code:
LrnDevEui: 0059AC000018173D
LrnFPort: 1
LrnInfos: null
AS_ID: TestingASID
Time: 2017-04-26T15:33:50.381 02:00
Token: 307d8d57a205ce792721648d9b3a6ba624804d6833ab0d55da4c79f87b11d92d


Ik hoop dat iemand mij kan vertellen wat ik over het hoofd zie.

Met vriendelijke groet
Reputatie 3
Badge +1
Als ik het goed begrijp wil je een bericht van KPN ontvangen op je Applicatieserver.

Ten eerste moet je de streepjes niet verwijderden uit je AS-Key, want dan krijg je een compleet ander SHA token. Daarnaast zie ik dat je gebruik maakt van de 'test'-functionaliteit vanaf het portal om de berichten te testen. Jammer genoeg stuurt een test bericht geen correcte token mee met het bericht.
Om een bericht te kunnen verifiëren zal je een bericht vanaf je LoRa Device moeten versturen. Dan krijg je een token mee die je kunt verifiëren.
Jammer dat is de validatie niet kan testen met jullie 'test'-functionaliteit. Ik zal eens kijken of ik het met een LoRa device wel voor elkaar krijg. Tevens lijkt het me wel een handige functionaliteit om eventueel toe te voegen aan jullie 'test'-functionaliteit.
I am trying to validate an Location packet and an Downlink_sent, but I can't get the tokens to be the same. I have all the correct body elements, but as there is no payload_hex in either of those messages I can't get an token wich is the same as the token in the query parameters.
Mensen, inderdaad mag de validatie beter uitgelegd worden! Een klein nuance-verschil in de inhoud van zo'n SHA256 functie, en je hebt een totaal verschillende uitkomst. Zo kwam ik er achter dat als je met de device-informatie werkt, het ASKey gelijk moet zijn aan het veld in je account (dus met streepjes). Verwerk ik de 'Test uplink' met dezelfde procedure dan krijg ik een verschillende uitkomst:
- De SHA256 is verschillend aan het meegestuurd token
- Time=2018-01-09T10:45:19.676+01:00 t.o.v. Time=2018-01-09T09:47:00.073Z (in de device situatie, probeert timezone informatie mee te sturen en blijft steken op 'Z')

Die 'Test uplink' krijg ik niet voor elkaar. Ik heb geprobeerd met ASKey zonder streepjes, ASKey gelijk aan het voorbeeld op de KPN-website.
Reputatie 3
Badge
Hi all,

Thank you all very much for your feedback on the token validation (and more specifically on the SHA-256 functionality). I will look into the possibility to further clarify this process (maybe in a new topic).
In the mean time, have you had a look at the reference code regarding this subject yet?
This was recently described in this topic.

Kind regards,
Lennart
I have the same problems as Kees DPD.
The "Test Uplink" always fails no matter what I use as ASKey variation.

I have tested with the exact reference code mentioned by Lennart Nordin but still no luck.
And I agree it is probably to do with the time format that is wrong. Any fixes for this?
Reputatie 1
Badge
I have the same problems as Kees DPD.
The "Test Uplink" always fails no matter what I use as ASKey variation.

I have tested with the exact reference code mentioned by Lennart Nordin but still no luck.
And I agree it is probably to do with the time format that is wrong. Any fixes for this?


Hi,
It is true that the token sent with the "Test Uplink" button, fails the validation. But for regular LoRa messages the validation is quite straightforward. Below is a node.js snippet that works for me. The AS_ID is used unmodified (ie., keeping the dashes).
code:

const crypto = require('crypto');

function ValidateSender(query, body)
{
let queryParams = `LrnDevEui=${query.LrnDevEui}&LrnFPort=${query.LrnFPort}&LrnInfos=${query.LrnInfos}&AS_ID=${query.AS_ID}&Time=${query.Time}`;
let bodyElements = body.CustomerID+body.DevEUI+body.FPort+body.FCntUp+body.payload_hex;

const hasher = crypto.createHash('sha256');
hasher.update(bodyElements + queryParams + ASKEY);
let token = hasher.digest('hex');

if (token != query.Token) {
console.log("Token mismatch!");
}
return token == query.Token;
}
Reputatie 7
Badge +11
Thanks so much for sharing @tonb, I highlighted your valuable post 😃

Reageer