Cannot decrypt FrmPayload using the function in brocaar/lorawan

Hello.

We had a server running for a few months and just now realized that we made a mistake in the way we saved data, meaning a lot of our measurements are incorrect. Luckily I saved all raw lorawan frames (non-decrypted, the raw ones received by MQTT) for a case like this - however, I am now stuck trying to figure out how to decrypt the FrmPayload field of all the old messages.

I have seen this post and a few similar ones, where the answer is to look at the EncryptFRMPayload function here: lorawan/phypayload.go at master · brocaar/lorawan · GitHub

I have tried using that function myself (both re-implementing in another language and just directly using that function in GO) but I cannot manage to get the same (correct) output as the one shown on Chirpstack in the device events page. I have tried all possible combinations of big and little-endianness for the netid, key, and payload, to no avail. Here is the test code:

Relevant info:

  • DevAddr: 01c104bf
  • Raw data (in the Frmpayload key on chirpstack): 39d6b5dbb79addf619ab6293123c02216a478c3437e9521940ead0dbe5bacb2e040da971677d822a
  • fcnt: 276
  • application key: 05DB39F25195B42DB1F1B6BE3C127F50

The data shown in chirpstack is FQQCwPqrLwQSuGkUAQIreFACOygCAlmpIAJdBhQMeARwOXIC/RcAAA==, which decoded as hex should be 150402c0faab2f0412b8691401022b7850023b28020259a920025d06140c780470397202fd170000.

For completeness, this is the packet decoded by chirpstack (showing in “events” under the device page):

{
  "deduplicationId": "f1ca964d-b63e-41f0-b2c0-39d7fa78cbf4",
  "time": "2023-05-03T07:27:04.226+00:00",
  "deviceInfo": {
    "tenantId": "fa972792-dea5-4143-883a-f76b797e4dd8",
    "tenantName": "ourname",
    "applicationId": "e489d616-5e79-4cd4-b6a0-cc9bea30b2a4",
    "applicationName": "fooapp",
    "deviceProfileId": "ad081270-988c-4a52-a157-f81aab5dfa21",
    "deviceProfileName": "foo",
    "deviceName": "bar",
    "devEui": "94193a010b0027fd",
    "tags": {}
  },
  "devAddr": "01c104bf",
  "adr": true,
  "dr": 0,
  "fCnt": 276,
  "fPort": 2,
  "confirmed": false,
  "data": "FQQCwPqrLwQSuGkUAQIreFACOygCAlmpIAJdBhQMeARwOXIC/RcAAA==",
  "rxInfo": [
    {
      "gatewayId": "7076ff0056070a51",
      "uplinkId": 18198,
      "timeSinceGpsEpoch": "1367134042.226s",
      "rssi": -116,
      "snr": -20.2,
      "location": {
        "latitude": xxx,
        "longitude": xxx,
        "altitude": xxx
      },
      "context": "PE1GdA==",
      "metadata": {
        "region_common_name": "EU868",
        "region_config_id": "eu868"
      }
    }
  ],
  "txInfo": {
    "frequency": 867100000,
    "modulation": {
      "lora": {
        "bandwidth": 125000,
        "spreadingFactor": 12,
        "codeRate": "CR_4_5"
      }
    }
  }
}

While this is the “raw” lorawan frame shown on chirpstack:

{
    "phy_payload": {
        "mhdr": {
            "m_type": "UnconfirmedDataUp",
            "major": "LoRaWANR1"
        },
        "mic": [83, 146, 168, 188],
        "payload": {
            "f_port": 2,
            "fhdr": {
                "devaddr": "01c104bf",
                "f_cnt": 276,
                "f_ctrl": {
                    "ack": False,
                    "adr": True,
                    "adr_ack_req": False,
                    "class_b": False,
                    "f_opts_len": 0,
                    "f_pending": False
                },
                "f_opts": []
            },
            "frm_payload": "39d6b5dbb79addf619ab6293123c02216a478c3437e9521940ead0dbe5bacb2e040da971677d822a"
        }
    },
    "rx_info": [
        {
            "context": "PE1GdA==",
            "gatewayId": "7076ff0056070a51",
            "location": {
                "altitude": xxx,
                "latitude": xxx,
                "longitude": xxx
            },
            "metadata": {
                "region_common_name": "EU868",
                "region_config_id": "eu868"
            },
            "rssi": -116,
            "snr": -20.200000762939453,
            "timeSinceGpsEpoch": "1367134042.226s",
            "uplinkId": 18198
        }
    ],
    "tx_info": {
        "frequency": 867100000,
        "modulation": {
            "lora": {
                "bandwidth": 125000,
                "codeRate": "CR_4_5",
                "spreadingFactor": 12
            }
        }
    }
}

What am I doing wrong?

It does not appear that either data or frm_payload field is a full lorawan packet. The header, port and mic are stripped?

https://lorawan-packet-decoder-0ta6puiniaut.runkit.sh/?data=FQQCwPqrLwQSuGkUAQIreFACOygCAlmpIAJdBhQMeARwOXIC%2FRcAAA%3D%3D&nwkskey=&appskey=

https://lorawan-packet-decoder-0ta6puiniaut.runkit.sh/?data=39d6b5dbb79addf619ab6293123c02216a478c3437e9521940ead0dbe5bacb2e040da971677d822a&nwkskey=&appskey=

Uplinks are encrypted with an app session key.

The appkey can only decrypt join accept packets if you have the nonces.

1 Like

I copy-pasted exactly what shows up in chirpstack :

The function I linked on github looks like it’s meant to decrypt the FRMPayload directly, not the full packet?

Any idea where this is described/where it happens in the code? Is it the same function but called with a session key rather than the app key? Where can I find the session key?

Ah, damn, yes, I missed that part. I need the session App key, not the App key. So all my past data is worthless? Is there any way to recover old app keys from logs or anywhere?

You would need join requests and accept packets to regenerate old session keys if they are not in the logs.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.