forked from Telos4/LoRa-Workshop
added uLoRaWAN library
This commit is contained in:
parent
cc9e9652cb
commit
e02cdb5242
75
micropython/uLoRaWAN/AES_CMAC.py
Normal file
75
micropython/uLoRaWAN/AES_CMAC.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
from struct import pack, unpack
|
||||
import ucryptolib
|
||||
MODE_ECB = 1
|
||||
|
||||
|
||||
class AES_CMAC:
|
||||
def gen_subkey(self, K):
|
||||
AES_128 = ucryptolib.aes(bytearray(K), MODE_ECB)
|
||||
|
||||
L = AES_128.encrypt(('\x00'*16).encode())
|
||||
|
||||
LHigh = unpack('>Q',L[:8])[0]
|
||||
LLow = unpack('>Q',L[8:])[0]
|
||||
|
||||
K1High = ((LHigh << 1) | ( LLow >> 63 )) & 0xFFFFFFFFFFFFFFFF
|
||||
K1Low = (LLow << 1) & 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
if (LHigh >> 63):
|
||||
K1Low ^= 0x87
|
||||
|
||||
K2High = ((K1High << 1) | (K1Low >> 63)) & 0xFFFFFFFFFFFFFFFF
|
||||
K2Low = ((K1Low << 1)) & 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
if (K1High >> 63):
|
||||
K2Low ^= 0x87
|
||||
|
||||
K1 = pack('>QQ', K1High, K1Low)
|
||||
K2 = pack('>QQ', K2High, K2Low)
|
||||
|
||||
return K1, K2
|
||||
|
||||
def xor_128(self, N1, N2):
|
||||
J = b''
|
||||
for i in range(len(N1)):
|
||||
J += bytes([N1[i] ^ N2[i]])
|
||||
return J
|
||||
|
||||
def pad(self, N):
|
||||
const_Bsize = 16
|
||||
padLen = 16-len(N)
|
||||
return N + b'\x80' + b'\x00'*(padLen-1)
|
||||
|
||||
def encode(self, K, M):
|
||||
const_Bsize = 16
|
||||
const_Zero = b'\x00'*16
|
||||
|
||||
AES_128 = ucryptolib.aes(bytearray(K), MODE_ECB)
|
||||
|
||||
K1, K2 = self.gen_subkey(K)
|
||||
n = int(len(M)/const_Bsize)
|
||||
|
||||
if n == 0:
|
||||
n = 1
|
||||
flag = False
|
||||
else:
|
||||
if (len(M) % const_Bsize) == 0:
|
||||
flag = True
|
||||
else:
|
||||
n += 1
|
||||
flag = False
|
||||
|
||||
M_n = M[(n-1)*const_Bsize:]
|
||||
if flag is True:
|
||||
M_last = self.xor_128(M_n,K1)
|
||||
else:
|
||||
M_last = self.xor_128(self.pad(M_n),K2)
|
||||
|
||||
X = const_Zero
|
||||
for i in range(n-1):
|
||||
M_i = M[(i)*const_Bsize:][:16]
|
||||
Y = self.xor_128(X, M_i)
|
||||
X = AES_128.encrypt(Y)
|
||||
Y = self.xor_128(M_last, X)
|
||||
T = AES_128.encrypt(Y)
|
||||
return T
|
104
micropython/uLoRaWAN/DataPayload.py
Normal file
104
micropython/uLoRaWAN/DataPayload.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
#
|
||||
# frm_payload: data(0..N)
|
||||
#
|
||||
from .AES_CMAC import AES_CMAC
|
||||
import math
|
||||
import ucryptolib
|
||||
MODE_ECB = 1
|
||||
|
||||
|
||||
class DataPayload:
|
||||
|
||||
def read(self, mac_payload, payload):
|
||||
self.mac_payload = mac_payload
|
||||
self.payload = payload
|
||||
|
||||
def create(self, mac_payload, key, args):
|
||||
self.mac_payload = mac_payload
|
||||
self.set_payload(key, 0x00, args['data'])
|
||||
|
||||
def length(self):
|
||||
return len(self.payload)
|
||||
|
||||
def to_raw(self):
|
||||
return self.payload
|
||||
|
||||
def set_payload(self, key, direction, data):
|
||||
self.payload = self.encrypt_payload(key, direction, data)
|
||||
|
||||
def compute_mic(self, key, direction, mhdr):
|
||||
mic = [0x49]
|
||||
mic += [0x00, 0x00, 0x00, 0x00]
|
||||
mic += [direction]
|
||||
mic += self.mac_payload.get_fhdr().get_devaddr()
|
||||
mic += self.mac_payload.get_fhdr().get_fcnt()
|
||||
mic += [0x00]
|
||||
mic += [0x00]
|
||||
mic += [0x00]
|
||||
mic += [1 + self.mac_payload.length()]
|
||||
mic += [mhdr.to_raw()]
|
||||
mic += self.mac_payload.to_raw()
|
||||
|
||||
cmac = AES_CMAC()
|
||||
computed_mic = cmac.encode(bytes(key), bytes(mic))[:4]
|
||||
return list(map(int, computed_mic))
|
||||
|
||||
def decrypt_payload(self, key, direction, mic):
|
||||
print(self.payload, key, direction, mic)
|
||||
k = int(math.ceil(len(self.payload) / 16.0))
|
||||
|
||||
a = []
|
||||
for i in range(k):
|
||||
a += [0x01]
|
||||
a += [0x00, 0x00, 0x00, 0x00]
|
||||
a += [direction]
|
||||
a += self.mac_payload.get_fhdr().get_devaddr()
|
||||
a += self.mac_payload.get_fhdr().get_fcnt()
|
||||
a += [0x00] # fcnt 32bit
|
||||
a += [0x00] # fcnt 32bit
|
||||
a += [0x00]
|
||||
a += [i+1]
|
||||
|
||||
cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
|
||||
s = cipher.encrypt(bytes(a))
|
||||
|
||||
padded_payload = []
|
||||
for i in range(k):
|
||||
idx = (i + 1) * 16
|
||||
padded_payload += (self.payload[idx - 16:idx] + ([0x00] * 16))[:16]
|
||||
|
||||
payload = []
|
||||
|
||||
for i in range(len(self.payload)):
|
||||
print(s[i], padded_payload[i], s[i] ^ padded_payload[i])
|
||||
payload += [s[i] ^ padded_payload[i]]
|
||||
|
||||
return list(map(int, payload))
|
||||
|
||||
def encrypt_payload(self, key, direction, data):
|
||||
k = int(math.ceil(len(data) / 16.0))
|
||||
|
||||
a = []
|
||||
for i in range(k):
|
||||
a += [0x01]
|
||||
a += [0x00, 0x00, 0x00, 0x00]
|
||||
a += [direction]
|
||||
a += self.mac_payload.get_fhdr().get_devaddr()
|
||||
a += self.mac_payload.get_fhdr().get_fcnt()
|
||||
a += [0x00] # fcnt 32bit
|
||||
a += [0x00] # fcnt 32bit
|
||||
a += [0x00]
|
||||
a += [i+1]
|
||||
|
||||
cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
|
||||
s = cipher.encrypt(bytes(a))
|
||||
|
||||
padded_payload = []
|
||||
for i in range(k):
|
||||
idx = (i + 1) * 16
|
||||
padded_payload += (data[idx - 16:idx] + ([0x00] * 16))[:16]
|
||||
|
||||
payload = []
|
||||
for i in range(len(data)):
|
||||
payload += [s[i] ^ padded_payload[i]]
|
||||
return list(map(int, payload))
|
25
micropython/uLoRaWAN/Direction.py
Normal file
25
micropython/uLoRaWAN/Direction.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from .MHDR import MHDR
|
||||
|
||||
|
||||
class Direction:
|
||||
|
||||
UP = 0x00
|
||||
DOWN = 0x01
|
||||
DIRECTION = {
|
||||
MHDR.JOIN_REQUEST: UP,
|
||||
MHDR.JOIN_ACCEPT: DOWN,
|
||||
MHDR.UNCONF_DATA_UP: UP,
|
||||
MHDR.UNCONF_DATA_DOWN: DOWN,
|
||||
MHDR.CONF_DATA_UP: UP,
|
||||
MHDR.CONF_DATA_DOWN: DOWN,
|
||||
MHDR.RFU: UP,
|
||||
MHDR.PROPRIETARY: UP }
|
||||
|
||||
def __init__(self, mhdr):
|
||||
self.set(mhdr)
|
||||
|
||||
def get(self):
|
||||
return self.direction
|
||||
|
||||
def set(self, mhdr):
|
||||
self.direction = self.DIRECTION[mhdr.get_mtype()]
|
66
micropython/uLoRaWAN/FHDR.py
Normal file
66
micropython/uLoRaWAN/FHDR.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# fhdr: devaddr(4) fctrl(1) fcnt(2) fopts(0..N)
|
||||
#
|
||||
from .MalformedPacketException import MalformedPacketException
|
||||
from .MHDR import MHDR
|
||||
#from struct import unpack
|
||||
|
||||
|
||||
class FHDR:
|
||||
|
||||
def read(self, mac_payload):
|
||||
if len(mac_payload) < 7:
|
||||
raise MalformedPacketException("Invalid fhdr")
|
||||
|
||||
self.devaddr = mac_payload[:4]
|
||||
self.fctrl = mac_payload[4]
|
||||
self.fcnt = mac_payload[5:7]
|
||||
self.fopts = mac_payload[7:7 + (self.fctrl & 0xf)]
|
||||
|
||||
def create(self, mtype, args):
|
||||
self.devaddr = [0x00, 0x00, 0x00, 0x00]
|
||||
self.fctrl = 0x00
|
||||
if 'fcnt' in args:
|
||||
self.fcnt = args['fcnt'].to_bytes(2, 'little')
|
||||
else:
|
||||
self.fcnt = [0x00, 0x00]
|
||||
self.fopts = []
|
||||
if mtype == MHDR.UNCONF_DATA_UP or mtype == MHDR.UNCONF_DATA_DOWN or\
|
||||
mtype == MHDR.CONF_DATA_UP or mtype == MHDR.CONF_DATA_DOWN:
|
||||
self.devaddr = list(reversed(args['devaddr']))
|
||||
|
||||
def length(self):
|
||||
return 4 + 1 + 2 + (self.fctrl & 0xf)
|
||||
|
||||
def to_raw(self):
|
||||
fhdr = []
|
||||
fhdr += self.devaddr
|
||||
fhdr += [self.fctrl]
|
||||
fhdr += self.fcnt
|
||||
if self.fopts:
|
||||
fhdr += self.fopts
|
||||
return fhdr
|
||||
|
||||
def get_devaddr(self):
|
||||
return self.devaddr
|
||||
|
||||
def set_devaddr(self, devaddr):
|
||||
self.devaddr = devaddr
|
||||
|
||||
def get_fctrl(self):
|
||||
return self.fctrl
|
||||
|
||||
def set_fctrl(self, fctrl):
|
||||
self.fctrl = fctrl
|
||||
|
||||
def get_fcnt(self):
|
||||
return self.fcnt
|
||||
|
||||
def set_fcnt(self, fcnt):
|
||||
self.fcnt = fcnt
|
||||
|
||||
def get_fopts(self):
|
||||
return self.fopts
|
||||
|
||||
def set_fopts(self, fopts):
|
||||
self.fopts = fopts
|
100
micropython/uLoRaWAN/JoinAcceptPayload.py
Normal file
100
micropython/uLoRaWAN/JoinAcceptPayload.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
#
|
||||
# frm_payload: appnonce(3) netid(3) devaddr(4) dlsettings(1) rxdelay(1) cflist(0..16)
|
||||
#
|
||||
from .MalformedPacketException import MalformedPacketException
|
||||
from .AES_CMAC import AES_CMAC
|
||||
import ucryptolib
|
||||
MODE_ECB = 1
|
||||
|
||||
class JoinAcceptPayload:
|
||||
|
||||
def read(self, payload):
|
||||
if len(payload) < 12:
|
||||
raise MalformedPacketException("Invalid join accept")
|
||||
self.encrypted_payload = payload
|
||||
|
||||
def create(self, args):
|
||||
pass
|
||||
|
||||
def length(self):
|
||||
return len(self.encrypted_payload)
|
||||
|
||||
def to_raw(self):
|
||||
return self.encrypted_payload
|
||||
|
||||
def to_clear_raw(self):
|
||||
return self.payload
|
||||
|
||||
def get_appnonce(self):
|
||||
return self.appnonce
|
||||
|
||||
def get_netid(self):
|
||||
return self.netid
|
||||
|
||||
def get_devaddr(self):
|
||||
return list(map(int, reversed(self.devaddr)))
|
||||
|
||||
def get_dlsettings(self):
|
||||
return self.dlsettings
|
||||
|
||||
def get_rxdelay(self):
|
||||
return self.rxdelay
|
||||
|
||||
def get_cflist(self):
|
||||
return self.cflist
|
||||
|
||||
def compute_mic(self, key, direction, mhdr):
|
||||
mic = []
|
||||
mic += [mhdr.to_raw()]
|
||||
mic += self.to_clear_raw()
|
||||
|
||||
cmac = AES_CMAC()
|
||||
computed_mic = cmac.encode(bytes(key), bytes(mic))[:4]
|
||||
return list(map(int, computed_mic))
|
||||
|
||||
def decrypt_payload(self, key, direction, mic):
|
||||
a = []
|
||||
a += self.encrypted_payload
|
||||
a += mic
|
||||
|
||||
cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
|
||||
self.payload = cipher.encrypt(bytes(a))[:-4]
|
||||
|
||||
self.appnonce = self.payload[:3]
|
||||
self.netid = self.payload[3:6]
|
||||
self.devaddr = self.payload[6:10]
|
||||
self.dlsettings = self.payload[10]
|
||||
self.rxdelay = self.payload[11]
|
||||
self.cflist = None
|
||||
if self.payload[12:]:
|
||||
self.cflist = self.payload[12:]
|
||||
|
||||
return list(map(int, self.payload))
|
||||
|
||||
def encrypt_payload(self, key, direction, mhdr):
|
||||
a = []
|
||||
a += self.to_clear_raw()
|
||||
a += self.compute_mic(key, direction, mhdr)
|
||||
|
||||
cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
|
||||
return list(map(int, cipher.decrypt(bytes(a))))
|
||||
|
||||
def derive_nwskey(self, key, devnonce):
|
||||
a = [0x01]
|
||||
a += self.get_appnonce()
|
||||
a += self.get_netid()
|
||||
a += devnonce
|
||||
a += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||||
|
||||
cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
|
||||
return list(map(int, cipher.encrypt(bytes(a))))
|
||||
|
||||
def derive_appskey(self, key, devnonce):
|
||||
a = [0x02]
|
||||
a += self.get_appnonce()
|
||||
a += self.get_netid()
|
||||
a += devnonce
|
||||
a += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||||
|
||||
cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
|
||||
return list(map(int, cipher.encrypt(bytes(a))))
|
50
micropython/uLoRaWAN/JoinRequestPayload.py
Normal file
50
micropython/uLoRaWAN/JoinRequestPayload.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# frm_payload: appeui(8) deveui(8) devnonce(2)
|
||||
#
|
||||
from .MalformedPacketException import MalformedPacketException
|
||||
from .AES_CMAC import AES_CMAC
|
||||
|
||||
|
||||
class JoinRequestPayload:
|
||||
|
||||
def read(self, payload):
|
||||
if len(payload) != 18:
|
||||
raise MalformedPacketException("Invalid join request")
|
||||
self.deveui = payload[8:16]
|
||||
self.appeui = payload[:8]
|
||||
self.devnonce = payload[16:18]
|
||||
|
||||
def create(self, args):
|
||||
self.deveui = list(reversed(args['deveui']))
|
||||
self.appeui = list(reversed(args['appeui']))
|
||||
self.devnonce = args['devnonce']
|
||||
|
||||
def length(self):
|
||||
return 18
|
||||
|
||||
def to_raw(self):
|
||||
payload = []
|
||||
payload += self.appeui
|
||||
payload += self.deveui
|
||||
payload += self.devnonce
|
||||
return payload
|
||||
|
||||
def get_appeui(self):
|
||||
return self.appeui
|
||||
|
||||
def get_deveui(self):
|
||||
return self.deveui
|
||||
|
||||
def get_devnonce(self):
|
||||
return self.devnonce
|
||||
|
||||
def compute_mic(self, key, direction, mhdr):
|
||||
mic = [mhdr.to_raw()]
|
||||
mic += self.to_raw()
|
||||
|
||||
cmac = AES_CMAC()
|
||||
computed_mic = cmac.encode(bytes(key), bytes(mic))[:4]
|
||||
return list(map(int, computed_mic))
|
||||
|
||||
def decrypt_payload(self, key, direction, mic):
|
||||
return self.to_raw()
|
34
micropython/uLoRaWAN/MHDR.py
Normal file
34
micropython/uLoRaWAN/MHDR.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
from .MalformedPacketException import MalformedPacketException
|
||||
|
||||
|
||||
class MHDR:
|
||||
|
||||
LORAWAN_V1 = 0x00
|
||||
|
||||
MHDR_TYPE = 0xE0
|
||||
MHDR_RFU = 0x1C
|
||||
MHDR_MAJOR = 0x03
|
||||
|
||||
JOIN_REQUEST = 0x00
|
||||
JOIN_ACCEPT = 0x20
|
||||
UNCONF_DATA_UP = 0x40
|
||||
UNCONF_DATA_DOWN = 0x60
|
||||
CONF_DATA_UP = 0x80
|
||||
CONF_DATA_DOWN = 0xA0
|
||||
RFU = 0xC0 # rejoin for roaming
|
||||
PROPRIETARY = 0xE0
|
||||
|
||||
def __init__(self, mhdr):
|
||||
self.mhdr = mhdr
|
||||
mversion = mhdr & self.MHDR_MAJOR
|
||||
if mversion != self.LORAWAN_V1:
|
||||
raise MalformedPacketException("Invalid major version")
|
||||
|
||||
def to_raw(self):
|
||||
return self.mhdr
|
||||
|
||||
def get_mversion(self):
|
||||
return self.mhdr & self.MHDR_MAJOR
|
||||
|
||||
def get_mtype(self):
|
||||
return self.mhdr & self.MHDR_TYPE
|
78
micropython/uLoRaWAN/MacPayload.py
Normal file
78
micropython/uLoRaWAN/MacPayload.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
#
|
||||
# mac_payload: fhdr(7..23) fport(1) frm_payload(0..N)
|
||||
#
|
||||
from .MalformedPacketException import MalformedPacketException
|
||||
from .FHDR import FHDR
|
||||
from .MHDR import MHDR
|
||||
from .JoinRequestPayload import JoinRequestPayload
|
||||
from .JoinAcceptPayload import JoinAcceptPayload
|
||||
from .DataPayload import DataPayload
|
||||
|
||||
|
||||
class MacPayload:
|
||||
|
||||
def read(self, mtype, mac_payload):
|
||||
if len(mac_payload) < 1:
|
||||
raise MalformedPacketException("Invalid mac payload")
|
||||
|
||||
self.fhdr = FHDR()
|
||||
self.fhdr.read(mac_payload)
|
||||
self.fport = mac_payload[self.fhdr.length()]
|
||||
self.frm_payload = None
|
||||
if mtype == MHDR.JOIN_REQUEST:
|
||||
self.frm_payload = JoinRequestPayload()
|
||||
self.frm_payload.read(mac_payload)
|
||||
if mtype == MHDR.JOIN_ACCEPT:
|
||||
self.frm_payload = JoinAcceptPayload()
|
||||
self.frm_payload.read(mac_payload)
|
||||
if mtype == MHDR.UNCONF_DATA_UP or mtype == MHDR.UNCONF_DATA_DOWN or\
|
||||
mtype == MHDR.CONF_DATA_UP or mtype == MHDR.CONF_DATA_DOWN:
|
||||
self.frm_payload = DataPayload()
|
||||
self.frm_payload.read(self, mac_payload[self.fhdr.length() + 1:])
|
||||
|
||||
def create(self, mtype, key, args):
|
||||
self.fhdr = FHDR()
|
||||
self.fhdr.create(mtype, args)
|
||||
self.fport = 0x01
|
||||
self.frm_payload = None
|
||||
if mtype == MHDR.JOIN_REQUEST:
|
||||
self.frm_payload = JoinRequestPayload()
|
||||
self.frm_payload.create(args)
|
||||
if mtype == MHDR.JOIN_ACCEPT:
|
||||
self.frm_payload = JoinAcceptPayload()
|
||||
self.frm_payload.create(args)
|
||||
if mtype == MHDR.UNCONF_DATA_UP or mtype == MHDR.UNCONF_DATA_DOWN or\
|
||||
mtype == MHDR.CONF_DATA_UP or mtype == MHDR.CONF_DATA_DOWN:
|
||||
self.frm_payload = DataPayload()
|
||||
self.frm_payload.create(self, key, args)
|
||||
|
||||
def length(self):
|
||||
return len(self.to_raw())
|
||||
|
||||
def to_raw(self):
|
||||
mac_payload = []
|
||||
if self.fhdr.get_devaddr() != [0x00, 0x00, 0x00, 0x00]:
|
||||
mac_payload += self.fhdr.to_raw()
|
||||
if self.frm_payload != None:
|
||||
if self.fhdr.get_devaddr() != [0x00, 0x00, 0x00, 0x00]:
|
||||
mac_payload += [self.fport]
|
||||
mac_payload += self.frm_payload.to_raw()
|
||||
return mac_payload
|
||||
|
||||
def get_fhdr(self):
|
||||
return self.fhdr
|
||||
|
||||
def set_fhdr(self, fhdr):
|
||||
self.fhdr = fhdr
|
||||
|
||||
def get_fport(self):
|
||||
return self.fport
|
||||
|
||||
def set_fport(self, fport):
|
||||
self.fport = fport
|
||||
|
||||
def get_frm_payload(self):
|
||||
return self.frm_payload
|
||||
|
||||
def set_frm_payload(self, frm_payload):
|
||||
self.frm_payload = frm_payload
|
2
micropython/uLoRaWAN/MalformedPacketException.py
Normal file
2
micropython/uLoRaWAN/MalformedPacketException.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
class MalformedPacketException(Exception):
|
||||
"""Custom Exception for LoRaWAN packet info"""
|
94
micropython/uLoRaWAN/PhyPayload.py
Normal file
94
micropython/uLoRaWAN/PhyPayload.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
#
|
||||
# lorawan packet: mhdr(1) mac_payload(1..N) mic(4)
|
||||
#
|
||||
from .MalformedPacketException import MalformedPacketException
|
||||
from .MHDR import MHDR
|
||||
from .Direction import Direction
|
||||
from .MacPayload import MacPayload
|
||||
|
||||
|
||||
class PhyPayload:
|
||||
|
||||
def __init__(self, nwkey, appkey):
|
||||
self.nwkey = nwkey
|
||||
self.appkey = appkey
|
||||
|
||||
def read(self, packet):
|
||||
if len(packet) < 12:
|
||||
raise MalformedPacketException("Invalid lorawan packet")
|
||||
|
||||
self.mhdr = MHDR(packet[0])
|
||||
self.set_direction()
|
||||
self.mac_payload = MacPayload()
|
||||
self.mac_payload.read(self.get_mhdr().get_mtype(), packet[1:-4])
|
||||
self.mic = packet[-4:]
|
||||
|
||||
|
||||
def create(self, mhdr, args):
|
||||
self.mhdr = MHDR(mhdr)
|
||||
self.set_direction()
|
||||
self.mac_payload = MacPayload()
|
||||
self.mac_payload.create(self.get_mhdr().get_mtype(), self.appkey, args)
|
||||
self.mic = None
|
||||
|
||||
def length(self):
|
||||
return len(self.to_raw())
|
||||
|
||||
def to_raw(self):
|
||||
phy_payload = [self.get_mhdr().to_raw()]
|
||||
phy_payload += self.mac_payload.to_raw()
|
||||
phy_payload += self.get_mic()
|
||||
return phy_payload
|
||||
|
||||
def get_mhdr(self):
|
||||
return self.mhdr
|
||||
|
||||
def set_mhdr(self, mhdr):
|
||||
self.mhdr = mhdr
|
||||
|
||||
def get_direction(self):
|
||||
return self.direction.get()
|
||||
|
||||
def set_direction(self):
|
||||
self.direction = Direction(self.get_mhdr())
|
||||
|
||||
def get_mac_payload(self):
|
||||
return self.mac_payload
|
||||
|
||||
def set_mac_payload(self, mac_payload):
|
||||
self.mac_payload = mac_payload
|
||||
|
||||
def get_mic(self):
|
||||
if self.mic == None:
|
||||
self.set_mic(self.compute_mic())
|
||||
return self.mic
|
||||
|
||||
def set_mic(self, mic):
|
||||
self.mic = mic
|
||||
|
||||
def compute_mic(self):
|
||||
if self.get_mhdr().get_mtype() == MHDR.JOIN_ACCEPT:
|
||||
return self.mac_payload.frm_payload.encrypt_payload(self.appkey, self.get_direction(), self.get_mhdr())[-4:]
|
||||
else:
|
||||
return self.mac_payload.frm_payload.compute_mic(self.nwkey, self.get_direction(), self.get_mhdr())
|
||||
|
||||
def valid_mic(self):
|
||||
if self.get_mhdr().get_mtype() == MHDR.JOIN_ACCEPT:
|
||||
return self.get_mic() == self.mac_payload.frm_payload.encrypt_payload(self.appkey, self.get_direction(), self.get_mhdr())[-4:]
|
||||
else:
|
||||
return self.get_mic() == self.mac_payload.frm_payload.compute_mic(self.nwkey, self.get_direction(), self.get_mhdr())
|
||||
|
||||
def get_devaddr(self):
|
||||
if self.get_mhdr().get_mtype() == MHDR.JOIN_ACCEPT:
|
||||
return self.mac_payload.frm_payload.get_devaddr()
|
||||
else:
|
||||
return self.mac_payload.fhdr.get_devaddr()
|
||||
|
||||
def get_payload(self):
|
||||
return self.mac_payload.frm_payload.decrypt_payload(self.appkey, self.get_direction(), self.mic)
|
||||
|
||||
def derive_nwskey(self, devnonce):
|
||||
return self.mac_payload.frm_payload.derive_nwskey(self.appkey, devnonce)
|
||||
|
||||
def derive_appskey(self, devnonce):
|
||||
return self.mac_payload.frm_payload.derive_appskey(self.appkey, devnonce)
|
10
micropython/uLoRaWAN/__init__.py
Normal file
10
micropython/uLoRaWAN/__init__.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
"""
|
||||
This is a port of library LoRaWAN to MicroPython using library ucryptolib.
|
||||
|
||||
"""
|
||||
from .PhyPayload import PhyPayload
|
||||
|
||||
|
||||
def new(nwkey=[], appkey=[]):
|
||||
return PhyPayload(nwkey, appkey)
|
Loading…
Reference in New Issue
Block a user