def prepare_lorawan_data(
            self,
            frmpayload,
            fport,
            mhdr=lorawan_parameters.MHDR.UNCONFIRMED_DOWN,
            fctr=lorawan_parameters.FCTRL.DOWN_ADROFF_ACKOFF_FPENDOFF_FOPTLEN0,
            fopts=b'',
            force_fcntdown_int=None):
        """
        Creates the PHYPayload of a LoRaWAN DATA message with the specified lorawan_parameters.
        It does the FRMPayload encryption and calculates de MIC using the device's keys.
        :param frmpayload: plain text of the FRMPayload (bytes)
        :param fport: frame port of the message (int)
        :param mhdr: MAC Header (1 byte)
        :param fctr: Frame control field of the Frame header (FHDR)
        :param fopts: Frame options field used to send MAC commands (0 to 15 bytes).
        :param force_fcntdown_int: Force the use of a forged downlink frame count
                                    (don't increase the downlink count).
        :return: bytes of the PHYPayload
        """
        if force_fcntdown_int:
            fcnt_down = force_fcntdown_int % 2**16
        else:
            fcnt_down = self.fcnt_down
            self.fcnt_down += 1

        if self.message_to_ack and mhdr in (b'\xA0', b'\x60'):
            fctr = struct.pack('B', struct.unpack('B', fctr)[0] | 32)

        fhdr = self.loramac_params.devaddr[::-1] + fctr + struct.pack(
            '<H', fcnt_down) + fopts
        mhdr_fhdr = mhdr + fhdr
        assert mhdr in (b'\x00', b'\x40', b'\x80', b'\x20', b'\x60', b'\xA0',
                        b'\xC0'), "Unrecognized MHDR."
        if mhdr in (b'\x00', b'\x40', b'\x80'):
            direction = 0
        else:
            direction = 1
        if fport is not None and frmpayload is not None:
            if fport == 0:
                key = self.loramac_params.nwkskey
            else:
                key = self.loramac_params.appskey
            mac_hdr_payload = mhdr_fhdr + struct.pack(
                'B', fport) + utils.encrypt_ieee802154(
                    key=key,
                    frmpayload=frmpayload,
                    direction=direction,
                    devaddr=self.loramac_params.devaddr,
                    fcnt=fcnt_down)
        else:
            mac_hdr_payload = mhdr_fhdr
        phy_payload = mac_hdr_payload + utils.mic_rfc4493(
            key=self.loramac_params.nwkskey,
            msg=mac_hdr_payload,
            direction=direction,
            devaddr=self.loramac_params.devaddr,
            fcnt=fcnt_down)
        return phy_payload
Example #2
0
 def test_downlink_encryption(self, device_session_id, default_test_key, dl_args, expected):
     """
     Tests the encryption for a downlink message with known plain text as the FRMPayload,
     and using different frame count (FCnt (2 bytes) field of the FHDR).
     """
     calculated = utils.encrypt_ieee802154(key=default_test_key,
                                           frmpayload=dl_args[0],
                                           direction=dl_args[1],
                                           devaddr=device_session_id["DevAddr"],
                                           fcnt=dl_args[2])
     assert calculated == expected
Example #3
0
    def get_frmpayload_plaintext(self, key):
        """  Return the FRMPayload plain text of a LoRaWAN data message when the content was encrypted used the
         provided key.

        :param key: byte sequence of the AppSKey used to encrypt the message (16 bytes).
        :return: byte sequence of the decrypted FRMPayload.
        """
        if self.macpayload.frmpayload_bytes is None or self.mhdr.mtype_str not in (
                'UNCONFIRMED_UP', 'UNCONFIRMED_DOWN', 'CONFIRMED_UP',
                'CONFIRMED_DOWN'):
            return None
        devaddr = self.macpayload.fhdr.devaddr_bytes
        fcnt = self.macpayload.fhdr.get_fcnt_int()
        plain_frmpayload = utils.encrypt_ieee802154(
            key=key,
            frmpayload=self.macpayload.frmpayload_bytes,
            direction=self.mhdr.message_dir,
            devaddr=devaddr,
            fcnt=fcnt)
        return plain_frmpayload
 def create_appmessage_str(self, appskey):
     """
     Decrypts the FRMPayload of the message and creates an Application Message
     :param appskey: byte sequence of the Application Session Key (16 bytes).
     :return: json formatted string.
     """
     lorawan_message = self.parse_lorawan_message()
     devaddr = lorawan_message.macpayload.fhdr.devaddr_bytes
     fcnt = lorawan_message.macpayload.fhdr.get_fcnt_int()
     plain_frmpayload = utils.encrypt_ieee802154(
         key=appskey,
         frmpayload=lorawan_message.macpayload.frmpayload_bytes,
         direction=lorawan_message.mhdr.message_dir,
         devaddr=devaddr,
         fcnt=fcnt)
     port = lorawan_message.macpayload.fport_int
     json_app_dict = self.testingtool_msg_dict
     json_app_dict["DevAddr"] = base64.b64encode(devaddr).decode()
     json_app_dict["FCnt"] = fcnt
     json_app_dict["Dir"] = lorawan_message.mhdr.message_dir
     json_app_dict["FPort"] = port
     json_app_dict["FRMPayload"] = base64.b64encode(
         plain_frmpayload).decode()
     return json.dumps(json_app_dict)