forked from Telos4/LoRa-Workshop
101 lines
2.7 KiB
Python
101 lines
2.7 KiB
Python
|
#
|
||
|
# 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))))
|