예제 #1
0
파일: __init__.py 프로젝트: mkuyper/liblora
def unpack_jreq(pdu:bytes) -> Msg:
    """Unpack JREQ message and extract fields without verifying the integrity of the message..
    This call helps locate the device key and then the integrity must be checked by calling verifyJoinRequest.
    Return None if message is malformed, otherwise return mapping with frame fields.
    """
    mhdr, aeui, deui, devnonce, mic = struct.unpack("<BQQHi", pdu[0:23])
    return { 'msgtype'  : 'jreq', 
             'MHdr'     : mhdr,
             'JoinEUI'  : rtlib.Eui(aeui),
             'DevEUI'   : rtlib.Eui(deui),
             'DevNonce' : devnonce,
             'MIC'      : mic
         }
예제 #2
0
파일: __init__.py 프로젝트: mkuyper/liblora
def pack_jreq (nwkkey:bytes,
               joineui:rtlib.Eui=None, deveui:rtlib.Eui=None,
               devnonce:int=0, mhdr:int=Major.V1|FrmType.JREQ) -> bytes:
    """Pack parameters into a JOIN REQUEST pdu with the following layout:
    |  1  |     8   |    8   |    2     |  4  |  bytes - all fields little endian
    | mhdr| joineui | deveui | devnonce | MIC |
    | < - - - - - - - - - - - - - - - ->|           input to MIC
    """
    if joineui is None: joineui = rtlib.Eui("00-00-00-00-00-00-00-00")
    if deveui  is None: deveui  = rtlib.Eui("00-00-00-00-00-00-00-00")
    
    pdu = struct.pack("<BqqHi", mhdr, joineui.as_int(), deveui.as_int(), devnonce & 0xFFFF, 0)
    mic = crypto.calcMicJoin(nwkkey,pdu)
    return pdu[0:-4] + struct.pack("<i", mic)
예제 #3
0
def mic_join_request(sstate: State, jrmsg: Msg) -> int:
    """Use the sstate['NwkKey'] to append or verify the MIC of the jrmsg.
    jsmsg must contain the following fields: 'MHdr', 'JoinEUI', 'DevEUI' and 'DevNonce'.
    The method computes a MIC over an encoding of the join request message and
    either sets the field 'MIC' if it is absent or compare the computed value with the value
    of this field. If they don't match a VerifyError is raised.
    """
    pdu = pack_jreq(to_bytes(sstate['NwkKey']), rtlib.Eui(jrmsg['JoinEUI']),
                    rtlib.Eui(jrmsg['DevEUI']), jrmsg['DevNonce'],
                    jrmsg.get('MHdr', Major.V1 | FrmType.JREQ))
    mic = struct.unpack("<i", pdu[-4:])[0]
    if 'MIC' in jrmsg:
        if jrmsg['MIC'] != mic:
            raise VerifyError('Verify of join request failed')
    else:
        jrmsg['MIC'] = mic
    return mic
예제 #4
0
파일: lorawan.py 프로젝트: mkuyper/basicmac
    def join(pdu:bytes, region:ld.Region, *, pdevnonce:int=-1, nwkkey:bytes=b'@ABCDEFGHIJKLMNO',
            appnonce:int=0, netid:int=1, devaddr:Optional[int]=None, dlset:Optional[int]=None, rxdly:int=0,
            **kwargs:Any) -> Tuple[bytes,Session]:
        jreq = lm.unpack_jreq(pdu)
        deveui = rt.Eui(jreq['DevEUI'])

        if devaddr is None:
            devaddr = numpy.int32(crc32(struct.pack('q', deveui)))
        if dlset is None:
            dlset = lm.DLSettings.pack(0, region.RX2DR, False)

        rx1droff, rx2dr, optneg = lm.DLSettings.unpack(dlset)

        lm.verify_jreq(nwkkey, pdu)

        cflist = region.get_cflist()

        devnonce = jreq['DevNonce']
        if pdevnonce >= devnonce:
            raise ValueError('DevNonce is not strictly increasing')

        nwkskey = lc.crypto.derive(nwkkey, devnonce, appnonce, netid, lm.KD_NwkSKey)
        appskey = lc.crypto.derive(nwkkey, devnonce, appnonce, netid, lm.KD_AppSKey)

        return lm.pack_jacc(nwkkey, appnonce, netid, devaddr, dlset, rxdly, cflist, devnonce=devnonce), {
                'deveui'    : deveui,
                'devaddr'   : devaddr,
                'nwkkey'    : nwkkey,
                'nwkskey'   : nwkskey,
                'appskey'   : appskey,
                'fcntup'    : 0,
                'fcntdn'    : 0,
                'rx1delay'  : max(rxdly, 1),
                'rx1droff'  : rx1droff,
                'rx2dr'     : rx2dr,
                'rx2freq'   : region.RX2Freq,
                'devnonce'  : devnonce,
                'region'    : region,
                }
예제 #5
0
    def process_join(self,
                     msg: LoraMsg,
                     rx2: bool = False,
                     **kwargs: Any) -> None:
        m = lm.unpack_nomic(msg.pdu)
        assert m['msgtype'] == 'jreq'

        nwkkey = kwargs.setdefault('nwkkey', b'@ABCDEFGHIJKLMNO')
        appnonce = kwargs.setdefault('appnonce', 0)
        netid = kwargs.setdefault('netid', 1)
        devaddr = kwargs.setdefault(
            'devaddr', numpy.int32(crc32(rt.Eui(m['DevEUI']).as_bytes())))
        rxdly = kwargs.setdefault('rxdly', 0)
        (rx1droff, rx2dr, optneg) = lm.DLSettings.unpack(
            kwargs.setdefault('dlset',
                              lm.DLSettings.pack(0, self.region.RX2DR, False)))

        lm.verify_jreq(nwkkey, msg.pdu)

        # check channel validity
        self.getupch(msg)

        # check that devnonce is increasing
        ldn = self.session.get('devnonce')
        devnonce = m['DevNonce']
        if ldn is not None and ldn >= devnonce:
            raise ValueError('DevNonce is not strictly increasing')

        nwkskey = lc.crypto.derive(nwkkey, devnonce, appnonce, netid,
                                   lm.KD_NwkSKey)
        appskey = lc.crypto.derive(nwkkey, devnonce, appnonce, netid,
                                   lm.KD_AppSKey)

        jacc = lm.pack_jacc(**kwargs)

        rxdelay = ld.JaccRxDelay
        if rx2:
            rxdelay += 1
            (freq, rps) = self.dn_rx2()
        else:
            (freq, rps) = self.up2dn_rx1(msg.freq, msg.rps, 0)

        self.add_dn(LoraMsg(msg.xend + rxdelay, jacc, freq, rps, 14))

        if self.sm and self.session:
            self.sm.remove(self.session)

        self.session = {
            'deveui': m['DevEUI'],
            'devaddr': devaddr,
            'nwkkey': nwkkey,
            'nwkskey': nwkskey,
            'appskey': appskey,
            'fcntup': 0,
            'fcntdn': 0,
            'rx1delay': max(rxdly, 1),
            'rx1droff': rx1droff,
            'rx2dr': rx2dr,
            'devnonce': devnonce,
        }

        if self.sm:
            self.sm.add(self.session)