Esempio n. 1
0
    def encrypt(self, key, dir):
        """Encrypt FRMPayload
        
        Args:
            key (int): AES encryption key - device NwkSKey or AppSkey
        
        """
        if self.payload.frmpayload == None:
            return
        plen = len(self.payload.frmpayload)
        if plen == 0:
            return
        k = int(math.ceil(plen / 16.0))
        # Create the concatenated block S
        S = ''
        for i in range(k):
            Ai = struct.pack('<BLBLLBB', 1, 0, dir, self.payload.fhdr.devaddr,
                             self.payload.fhdr.fcnt, 0, i + 1)
            S += aesEncrypt(intPackBytes(key, 16), Ai)

        # Pad frmpayload to a byte multiple of 16
        pad = k * 16 - plen
        ppl = self.payload.frmpayload + intPackBytes(0, pad)

        # Perform the XOR function over the data: unpack 8 bytes
        # to long long ints, XOR and repack
        pld = ''
        for i in range(k):
            s = struct.unpack('Q', S[i * 8:(i + 1) * 8])[0]
            p = struct.unpack('Q', ppl[i * 8:(i + 1) * 8])[0]
            pld += struct.pack('Q', s ^ p)
        # Truncate the result to the original frmpayload length
        self.payload.frmpayload = pld[:plen]
Esempio n. 2
0
    def encode(self):
        """Create a binary representation of JoinAcceptMessage object.
        
        Returns:
            Packed JoinAccept message.
        """
        # Encoding Join-accept:
        # MAC Header
        # 3 bytes appnonce
        # 3 bytes netid
        # 4 bytes devaddr
        # 1 byte dlsettings
        # 1 byte rxdelay
        # Optional cflist

        # Create the message
        header = self.mhdr.encode()
        msg =  intPackBytes(self.appnonce, 3, endian='little') + \
               intPackBytes(self.netid, 3, endian='little') + \
               struct.pack('<L', self.devaddr) + \
               struct.pack('B', self.dlsettings) + \
               struct.pack('B', self.rxdelay)
        # CFList is not used in a Join Accept message for US/AU bands
        if self.cflist:
            pass
        # Create the MIC over the entire message
        self.mic = aesEncrypt(intPackBytes(self.appkey, 16),
                              header + msg,
                              mode='CMAC')[0:4]
        msg += self.mic
        # Add the header and encrypt the message using AES-128 decrypt
        data = header + aesDecrypt(intPackBytes(self.appkey, 16), msg)
        return data
Esempio n. 3
0
    def checkMIC(self, appkey):

        # MIC is calculated over the binary join request message
        # excluding the MIC. Use the first four bytes of encrypted
        # data, convert from little endian data to int.
        data = self.mhdr.encode() + struct.pack('<QQH', self.appeui,
                                                self.deveui, self.devnonce)
        aesdata = aesEncrypt(intPackBytes(appkey, 16), data, mode='CMAC')
        mic = struct.unpack('<L', aesdata[:4])[0]
        return mic == self.mic
Esempio n. 4
0
    def checkMIC(self, key):
        """Check the message integrity code
        
        Args:
            key (int): NwkSkey
        
        Returns:
            True on success, False otherwise
        """

        # Calculate the MIC for this message using key
        msg = self.mhdr.encode() + self.payload.encode()
        B0 = struct.pack('<BLBLLBB', int('0x49', 16), 0, 0,
                         self.payload.fhdr.devaddr, self.payload.fhdr.fcnt, 0,
                         len(msg))
        data = B0 + msg
        aesdata = aesEncrypt(intPackBytes(key, 16), data, mode='CMAC')
        mic = struct.unpack('<L', aesdata[:4])[0]
        # Compare to message MIC
        return mic == self.mic
Esempio n. 5
0
 def _createSessionKey(self, pre, app, msg):
     """Create a NwkSKey or AppSKey
     
     Creates the session keys NwkSKey and AppSKey specific for
     an end-device to encrypt and verify network communication
     and application data.
     
     Args:
         pre (int): 0x01 ofr NwkSKey, 0x02 for AppSKey
         app (Application): The applicaiton object.
         msg (JoinRequestMessage): The MAC Join Request message.
     
     Returns:
         int: 128 bit session key
     """
     # Session key data: 0x0n | appnonce | netid | devnonce | pad (16)
     data = struct.pack('B', pre) + \
            intPackBytes(app.appnonce, 3, endian='little') + \
            intPackBytes(self.config.netid, 3, endian='little') + \
            struct.pack('<H', msg.devnonce) + intPackBytes(0, 7)
     aesdata = aesEncrypt(intPackBytes(app.appkey, 16), data)
     key = intUnpackBytes(aesdata)
     return key
Esempio n. 6
0
 def encode(self):
     """Create a binary representation of MACMessage object.
     
     Returns:
         String of packed data.
     
     """
     # Calculate the MIC.
     # The MIC is calculated as cmac = aes128_cmac(NwkSKey, B0 | msg)
     # MIC = cmac[0:3]
     # msg is defined as: MHDR | FHDR | FPort | FRMPayload
     # B0 is defined as:
     # 1 byte 0x49 | 4 bytes 0x00 | 1 byte dir=0 for uplink, 1 for downlink
     # 4 bytes devaddr | 4 bytes fcntup or fcntdown
     # 1 byte 0x00 | 1 bytes len
     msg = self.mhdr.encode() + self.payload.encode()
     B0 = struct.pack('<BLBLLBB', int('0x49', 16), 0, 1, self.devaddr,
                      self.payload.fhdr.fcnt, 0, len(msg))
     data = B0 + msg
     # Create the MIC over the entire message
     self.mic = aesEncrypt(intPackBytes(self.key, 16), data,
                           mode='CMAC')[0:4]
     msg += self.mic
     return msg