def kbencrypt(pkt, data, key = None, verbose = None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error("Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error("Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error("Could not import zigbee_crypt extension, cryptographic functionality is not available.") return None f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data nonce = "" # build the nonce nonce += struct.pack(">Q", f['source']) nonce += struct.pack(">I", f['fc']) fc = (f['reserved1'] << 6) | (f['extended_nonce'] << 5) | (f['key_type'] << 3) | f['reserved2'] nonce += chr(fc | 0x05) if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') crop_size = 4 + 2 # the size of all the zigbee crap, minus the length of the mic and FCS # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later reserved2 = pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = (pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] | 0x05) zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() zigbeeData = zigbeeData[:-crop_size] pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = reserved2 (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + mic.encode('hex') # Set pkt's values to reflect the encrypted ones to it's ready to be sent f['data'] = payload f['mic'] = struct.unpack(">I", mic)[0] return pkt
def kbencrypt(pkt, data, key = None, verbose = None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error("Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error("Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error("Could not import zigbee_crypt extension, cryptographic functionality is not available.") return None f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data nonce = "" # build the nonce nonce += struct.pack(">Q", f['source']) nonce += struct.pack(">I", f['fc']) fc = (f['reserved1'] << 6) | (f['extended_nonce'] << 5) | (f['key_type'] << 3) | f['nwk_seclevel'] nonce += chr(fc | 0x05) if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') crop_size = 4 + 2 # the size of all the zigbee crap, minus the length of the mic and FCS # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later reserved2 = pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = (pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] | 0x05) zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() zigbeeData = zigbeeData[:-crop_size] pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = reserved2 (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + mic.encode('hex') # Set pkt's values to reflect the encrypted ones to it's ready to be sent f['data'] = payload f['mic'] = struct.unpack(">I", mic)[0] return pkt
def kbencrypt(source_pkt, data, key=None, verbose=None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error( "Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error( "Invalid encryption key, must be a 16 byte string.") return None if not source_pkt.haslayer(ZigbeeSecurityHeader): log_killerbee.error( "Cannot encrypt frame without a ZigbeeSecurityHeader.") return None if not source_pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeNWK.") return None try: import zigbee_crypt except ImportError: log_killerbee.error( "Could not import zigbee_crypt extension, cryptographic functionality is not available." ) return None # This function destroys the packet, therefore work on a copy - @cutaway pkt = source_pkt.copy() # DOT154_CRYPT_ENC_MIC32 is always used regardless of what is claimed in OTA packet, so we will force it here. # This is done because the value of nwk_seclevel in the ZigbeeSecurityHeader does # not have to be accurate in the transmitted frame: the Zigbee NWK standard states that # the nwk_seclevel should be overwritten in the received frame with the value that is being # used by all nodes in the Zigbee network - this is to ensure that unencrypted frames can't be # maliciously injected. i.e. the receiver shouldn't trust the received nwk_seclevel. pkt.nwk_seclevel = DOT154_CRYPT_ENC_MIC32 # clear data and mic as we are about to create them pkt.data = '' pkt.mic = '' if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data # create NONCE (for crypt) and zigbeeData (for MIC) according to packet type sec_ctrl_byte = str(pkt[ZigbeeSecurityHeader])[0] if pkt.haslayer(ZigbeeAppDataPayload): nonce = struct.pack('L', source_pkt[ZigbeeNWK].ext_src) + struct.pack( 'I', source_pkt[ZigbeeSecurityHeader].fc) + sec_ctrl_byte zigbeeData = pkt[ZigbeeAppDataPayload].do_build() else: nonce = struct.pack( 'L', source_pkt[ZigbeeSecurityHeader].source) + struct.pack( 'I', source_pkt[ZigbeeSecurityHeader].fc) + sec_ctrl_byte zigbeeData = pkt[ZigbeeNWK].do_build() # minimum security level is DOT154_CRYPT_ENC_MIC32 but provide more if requested miclen = kbgetmiclen(source_pkt.nwk_seclevel) if miclen < 4: miclen = 4 (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, miclen, decrypted, zigbeeData) if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tZigbeeData: " + zigbeeData.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + mic.encode('hex') # According to comments in e.g. https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-zbee-security.c nwk_seclevel is not used any more but # we should reconstruct and return what was asked for anyway. pkt.data = payload + mic pkt.nwk_seclevel = source_pkt.nwk_seclevel ota_miclen = kbgetmiclen(pkt.nwk_seclevel) if ota_miclen > 0: pkt.mic = pkt.data[-ota_miclen:] pkt.data = pkt.data[:-ota_miclen] return pkt
def kbencrypt(pkt, data, key=None, verbose=None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error( "Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error( "Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error( "Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error( "Could not import zigbee_crypt extension, cryptographic functionality is not available." ) return None if verbose > 2: print "NWK SEC Details:" + str(pkt.nwk_seclevel) pkt = pkt.copy() #this is hack to fix the below line pkt.nwk_seclevel = 5 f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data #nonce = "" # build the nonce #nonce += struct.pack(">Q", f['source']) #nonce += struct.pack(">I", f['fc']) #fc = (f['reserved1'] << 6) | (f['extended_nonce'] << 5) | (f['key_type'] << 3) | f['reserved2'] #nonce += chr(fc | 0x05) sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0] nonce = struct.pack('L', f['source']) + struct.pack( 'I', f['fc']) + sec_ctrl_byte zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() if pkt.getlayer(ZigbeeSecurityHeader).mic == '': crop_size = 0 else: crop_size = len( pkt.getlayer(ZigbeeSecurityHeader).mic ) # the size of all the zigbee crap, minus the length of the mic and FCS zigbeeData = zigbeeData[:-crop_size] # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later #reserved2 = pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] #pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = (pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] | 0x05) #zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() #zigbeeData = zigbeeData[:-crop_size] #pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = reserved2 if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') print "\tZigbee data: " + zigbeeData.encode('hex') #delete mic from decrypted data #decrypted = decrypted[:-4] (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') #print "\tMic unpack: " + struct.unpack(">I", mic)[0] print "\tMic encode: " + mic.encode('hex') pkt.nwk_seclevel = 0 # Set pkt's values to reflect the encrypted ones to it's ready to be sent # add mic to payload for consistency with other functions f['data'] = payload #f['mic'] = struct.unpack(">I", mic)[0] #f['mic'] = mic pkt.getlayer(ZigbeeSecurityHeader).mic = mic return pkt
def kbencrypt(pkt, data, key = None, verbose = None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error("Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error("Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error("Could not import zigbee_crypt extension, cryptographic functionality is not available.") return None print "NWK SEC Details:" + str(pkt.nwk_seclevel) pkt = pkt.copy() # this is hack to fix the below line pkt.nwk_seclevel = 5 f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data # nonce = "" # build the nonce # nonce += struct.pack(">Q", f['source']) # nonce += struct.pack(">I", f['fc']) # fc = (f['reserved1'] << 6) | (f['extended_nonce'] << 5) | (f['key_type'] << 3) | f['reserved2'] # nonce += chr(fc | 0x05) sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0] nonce = struct.pack('Q', f['source']) + struct.pack('I', f['fc']) + sec_ctrl_byte zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() if pkt.getlayer(ZigbeeSecurityHeader).mic == '': crop_size = 0 else: crop_size = len(pkt.getlayer(ZigbeeSecurityHeader).mic) # the size of all the zigbee crap, minus the length of the mic and FCS zigbeeData = zigbeeData[:-crop_size] # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later # reserved2 = pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] # pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = (pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] | 0x05) # zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() # zigbeeData = zigbeeData[:-crop_size] # pkt.getlayer(ZigbeeSecurityHeader).fields['reserved2'] = reserved2 if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') print "\tZigbee data: " + zigbeeData.encode('hex') # delete mic from decrypted data decrypted = decrypted[:-4] (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') # print "\tMic unpack: " + struct.unpack(">I", mic)[0] print "\tMic encode: " + mic.encode('hex') pkt.nwk_seclevel = 0 # Set pkt's values to reflect the encrypted ones to it's ready to be sent # add mic to payload for consistency with other functions f['data'] = payload # f['mic'] = struct.unpack(">I", mic)[0] # f['mic'] = mic pkt.getlayer(ZigbeeSecurityHeader).mic = mic return pkt
def kbencrypt(pkt, data, key = None, verbose = None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error("Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error("Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error("Could not import zigbee_crypt extension, cryptographic functionality is not available.") return None pkt = pkt.copy() pkt.nwk_seclevel=5 #the issue appears to be when this is set f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say pkt.mic = '' # Clear out MIC if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0] nonce = struct.pack('L',f['source'])+struct.pack('I',f['fc']) + sec_ctrl_byte if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later zigbeeData = pkt.getlayer(ZigbeeNWK).do_build() # zigbeeData = octet string a = NwkHeader || AuxiliaryHeader # decrypted = octet string m = Payload (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + str(mic).encode('hex') # Set pkt's values to reflect the encrypted ones to it's ready to be sent f['data'] = payload f['mic'] = mic # 4.3.1.1 Security Processing of Outgoing Frames - Step 8 # Overwrite network security level field with '000' f['nwk_seclevel'] = 0 return pkt
def kbencrypt(pkt, data, key=None, verbose=None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error( "Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error( "Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error( "Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error( "Could not import zigbee_crypt extension, cryptographic functionality is not available." ) return None f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data # Soteria: Build the nonce the same way it is built by the decryption method: pkt = pkt.copy() #this is hack to fix the below line pkt.nwk_seclevel = 5 #the issue appears to be when this is set # Soteria: Omit the last 4 bytes of the MIC: crop_size = 4 zigbeeData = pkt.getlayer(ZigbeeNWK).do_build()[:-crop_size] sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0] nonce = struct.pack('L', f['source']) + struct.pack( 'I', f['fc']) + sec_ctrl_byte if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + mic.encode('hex') # Set pkt's values to reflect the encrypted ones to it's ready to be sent f['data'] = payload # Soteria: MIC field encoding type is ASCII, thus Storing the mic in hex version: # f['mic'] = struct.unpack(">I", mic)[0] f['mic'] = mic # Soteria: Update MIC and encrypted data pkt.getlayer(ZigbeeSecurityHeader).fields = f return pkt
def kbencrypt(pkt, data, key = None, verbose = None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error("Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error("Invalid encryption key, must be a 16 byte string.") return None elif not pkt.haslayer(ZigbeeSecurityHeader) or not pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeSecurityHeader.") return None try: import zigbee_crypt except ImportError: log_killerbee.error("Could not import zigbee_crypt extension, cryptographic functionality is not available.") return None f = pkt.getlayer(ZigbeeSecurityHeader).fields f['data'] = '' # explicitly clear it out, this should go without say if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data # Soteria: Build the nonce the same way it is built by the decryption method: pkt = pkt.copy() #this is hack to fix the below line pkt.nwk_seclevel=5 #the issue appears to be when this is set # Soteria: Omit the last 4 bytes of the MIC: crop_size = 4 zigbeeData = pkt.getlayer(ZigbeeNWK).do_build()[:-crop_size] sec_ctrl_byte = str(pkt.getlayer(ZigbeeSecurityHeader))[0] nonce = struct.pack('L',f['source'])+struct.pack('I',f['fc']) + sec_ctrl_byte if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + mic.encode('hex') # Set pkt's values to reflect the encrypted ones to it's ready to be sent f['data'] = payload # Soteria: MIC field encoding type is ASCII, thus Storing the mic in hex version: # f['mic'] = struct.unpack(">I", mic)[0] f['mic'] = mic # Soteria: Update MIC and encrypted data pkt.getlayer(ZigbeeSecurityHeader).fields = f return pkt
def kbencrypt(source_pkt, data, key = None, verbose = None): """Encrypt Zigbee frames using AES CCM* with 32-bit MIC""" if verbose is None: verbose = conf.verb if key == None: if conf.killerbee_nkey == None: log_killerbee.error("Cannot find decryption key. (Set conf.killerbee_nkey)") return None key = conf.killerbee_nkey if len(key) != 16: log_killerbee.error("Invalid encryption key, must be a 16 byte string.") return None if not source_pkt.haslayer(ZigbeeSecurityHeader): log_killerbee.error("Cannot encrypt frame without a ZigbeeSecurityHeader.") return None if not source_pkt.haslayer(ZigbeeNWK): log_killerbee.error("Cannot encrypt frame without a ZigbeeNWK.") return None try: import zigbee_crypt except ImportError: log_killerbee.error("Could not import zigbee_crypt extension, cryptographic functionality is not available.") return None #TODO: Investigate and issue a different fix: # https://code.google.com/p/killerbee/issues/detail?id=30 # This function destroys the packet, therefore work on a copy - @cutaway nwk_seclevel = source_pkt.nwk_seclevel pkt = source_pkt.copy() #this is hack to fix the below line pkt.nwk_seclevel=5 #the issue appears to be when this is set # Now recreate 'pkt' by rebuilding the raw data and creating a new scapy Packet, because # scapy splits the data/mic according to the nwk_seclevel in the ZigbeeSecurityHeader when # the scapy Packet is created. The value of nwk_seclevel in the ZigbeeSecurityHeader does # not have to be accurate in the transmitted frame: the Zigbee NWK standard states that # the nwk_seclevel should be overwritten in the received frame with the value that is being # used by all nodes in the Zigbee network - this is to ensure that unencrypted frames can't be # maliciously injected. i.e. the receiver shouldn't trust the received nwk_seclevel. newpkt = pkt.build() if pkt.haslayer(Dot15d4FCS): pkt = Dot15d4FCS(newpkt) else: pkt = Dot15d4(newpkt) pkt[ZigbeeSecurityHeader].data = '' if isinstance(data, Packet): decrypted = data.do_build() else: decrypted = data sec_ctrl_byte = str(pkt[ZigbeeSecurityHeader])[0] nonce = struct.pack('L',pkt[ZigbeeSecurityHeader].source)+struct.pack('I',pkt[ZigbeeSecurityHeader].fc) + sec_ctrl_byte if verbose > 2: print "Encrypt Details:" print "\tKey: " + key.encode('hex') print "\tNonce: " + nonce.encode('hex') print "\tDecrypted Data: " + decrypted.encode('hex') crop_size = 4 + len(pkt[ZigbeeSecurityHeader].data) # the Security Control Field flags have to be adjusted before this is calculated, so we store their original values so we can reset them later pkt[ZigbeeSecurityHeader].nwk_seclevel = (pkt[ZigbeeSecurityHeader].nwk_seclevel | 0x05) zigbeeData = pkt[ZigbeeNWK].do_build() zigbeeData = zigbeeData[:-crop_size] pkt[ZigbeeSecurityHeader].nwk_seclevel = nwk_seclevel (payload, mic) = zigbee_crypt.encrypt_ccm(key, nonce, 4, decrypted, zigbeeData) if verbose > 2: print "\tEncrypted Data: " + payload.encode('hex') print "\tMic: " + mic.encode('hex') # Set pkt's values to reflect the encrypted ones to it's ready to be sent # note that calculated mic is for the encrypted sublayer, not the enclosing packet # TODO: calculate mic for overall packet if required pkt[ZigbeeSecurityHeader].data = payload + mic pkt[ZigbeeSecurityHeader].mic = '' return pkt