def smart_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.smart_encrypt_pwd = password # Encryot SwapPacket and CcPacket fields if decrypt: self.nonce ^= password.data[9] self.function ^= password.data[11] ^ self.nonce self.srcAddress ^= password.data[10] ^ self.nonce self.regAddress ^= password.data[8] ^ self.nonce self.regId ^= password.data[7] ^ self.nonce if self.value is not None: pos = 0 newarray = [] for byte in self.value.toList(): byte ^= password.data[pos] ^ self.nonce newarray.append(byte) pos += 1 if pos == 11: pos = 0 self.value = SwapValue(newarray) if not decrypt: self.nonce ^= password.data[9] self._update_ccdata()
def setValue(self, value): """ Set parameter value @param value: New parameter value """ # Convert to SwapValue if value.__class__ is SwapValue: # Incorrect length? if self.value.getLength() != value.getLength(): return self.value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException( value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in ["on", "open", "1", "true", "enabled"]: res = 1 else: res = 0 else: # SwapType.STRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Convert to integer res = int(res) self.value = SwapValue(res, length) # Update current value self.value = SwapValue(res, length) # Update time stamp self.lastupdate = time.time() # Update register value self.register.update()
def setValue(self, value): """ Set parameter value @param value: New parameter value """ # Convert to SwapValue if value.__class__ is SwapValue: # Incorrect length? if self.value.getLength() != value.getLength(): return self.value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException(value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in ["on", "open", "1", "true", "enabled"]: res = 1 else: res = 0 else: # SwapType.STRING, SwapType.BSTRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Convert to integer res = int(res) self.value = SwapValue(res, length) # Update current value self.value = SwapValue(res, length) # Update time stamp self.lastupdate = time.time() # Update register value self.register.update()
def restart(self): """ Ask mote to restart @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(SwapState.RESTART, length=1) return self.cmdRegisterWack(SwapRegId.ID_SYSTEM_STATE, val)
def leaveSync(self): """ Ask mote to leave SYNC mode (RXON state) @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(SwapState.RXOFF, length=1) return self.cmdRegisterWack(SwapRegId.ID_SYSTEM_STATE, val)
def setAddress(self, address): """ Set mote address @param address: New mote address @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(address, length=1) return self.cmdRegisterWack(SwapRegId.ID_DEVICE_ADDR, val)
def setSecurity(self, secu): """ Set mote's security option. Return true if ACK received from mote @param secu: Security option @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(secu, length=1) return self.cmdRegisterWack(SwapRegId.ID_SECU_OPTION, val)
def setFreqChannel(self, channel): """ Set mote's frequency channel. Return true if ACK received from mote @param channel: New frequency channel @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(channel, length=1) res = self.cmdRegisterWack(SwapRegId.ID_FREQ_CHANNEL, val)
def setTxInterval(self, interval): """ Set periodic Tx interval. Return true if ACK received from mote @param interval: New Tx interval @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(interval, length=2) return self.cmdRegisterWack(SwapRegId.ID_TX_INTERVAL, val)
def setNetworkId(self, netId): """ Set mote's network id. Return true if ACK received from mote @param netId: New Network ID @return True if this command is confirmed from the mote. Return False otherwise """ val = SwapValue(netId, length=2) return self.cmdRegisterWack(SwapRegId.ID_NETWORK_ID, val)
def save_txinterval_command(self, interval): """ Save Tx Interval command for later transmission @param interval: New Tx Interval @return True if the command has been received by the target device False if the command was not received by the target device None if the command has been saved for later transmission """ val = SwapValue(interval, length=2) return self.save_command(SwapRegId.ID_TX_INTERVAL, val)
def save_address_command(self, address): """ Save address command for later transmission @param address: New mote address @return True if the command has been received by the target device False if the command was not received by the target device None if the command has been saved for later transmission """ val = SwapValue(address, length=1) return self.save_command(SwapRegId.ID_DEVICE_ADDR, val)
def __init__(self, ccPacket=None, destAddr=SwapAddress.BROADCAST_ADDR, hop=0, nonce=0, function=SwapFunction.STATUS, regAddr=0, regId=0, value=None, extended_addr=False): """ Class constructor @param ccPacket: Raw CcPacket where to take the information from @param destAddr: Destination address @param hop: Transmission hop count @param nonce: Security nonce @param function: SWAP function code (see SwapDefs.SwapFunction for more details) @param regAddr: Register address (address of the mote where the register really resides) @param regId: Register ID @param value: Register value """ CcPacket.__init__(self) ## Extended address disabled by default self.extended_address = extended_addr ## Destination address self.destAddress = destAddr ## Source address self.srcAddress = regAddr ## Hop count for repeating purposes self.hop = hop ## Security option self.security = 0 ## Security nonce self.nonce = nonce ## Function code self.function = function ## Register address self.regAddress = regAddr ## Register ID self.regId = regId ## SWAP value self.value = value if ccPacket is not None: if len(ccPacket.data) < 7: raise SwapException("Packet received is too short") # Hop count for repeating purposes self.hop = (ccPacket.data[2] >> 4) & 0x0F # Security option self.security = ccPacket.data[2] & 0x0F # Security nonce self.nonce = ccPacket.data[3] # Superclass attributes ## RSSI byte self.rssi = ccPacket.rssi ## LQI byte self.lqi = ccPacket.lqi ## CcPacket data field self.data = ccPacket.data # Smart Encryption enabled? if self.security & 0x02 and SwapPacket.smart_encrypt_pwd is not None: # Decrypt packet self.smart_encryption(SwapPacket.smart_encrypt_pwd, decrypt=True) # AES-128 Encryption enabled? elif self.security & 0x04 and SwapPacket.aes_encrypt_pwd is not None: # Decrypt packet self.aes_encryption(SwapPacket.aes_encrypt_pwd, decrypt=True) elif self.security & 0x06: return # Function code self.function = ccPacket.data[4] & 0x7F # Extended address indicator self.extended_address = (ccPacket.data[4] & 0x80) != 0 if self.extended_address: # Destination address self.destAddress = (ccPacket.data[0] << 8) | ccPacket.data[1] # Source address self.srcAddress = (ccPacket.data[5] << 8) | ccPacket.data[6] # Register address self.regAddress = (ccPacket.data[7] << 8) | ccPacket.data[8] # Register ID self.regId = ccPacket.data[9] # Register value if len(ccPacket.data) >= 11: self.value = SwapValue(ccPacket.data[10:]) else: # Destination address self.destAddress = ccPacket.data[0] # Source address self.srcAddress = ccPacket.data[1] # Register address self.regAddress = ccPacket.data[5] # Register ID self.regId = ccPacket.data[6] # Register value if len(ccPacket.data) >= 8: self.value = SwapValue(ccPacket.data[7:]) else: self._update_ccdata()
class SwapParam: """ Generic SWAP parameter, integrated into a SWAP register """ def getRegAddress(self): """ Return register address of the current parameter @return Register address """ return self.register.getAddress() def getRegId(self): """ Return register ID of the current parameter @return Register ID """ return self.register.id def update(self): """ Update parameter's value, posibly after a change in its parent register """ self.valueChanged = False if self.register is None: raise SwapException("Register not specified for current endpoint") return # Current register value converted to list lstRegVal = self.register.value.toList() # Total bits to be copied indexReg = self.bytePos shiftReg = 7 - self.bitPos bitsToCopy = self.byteSize * 8 + self.bitSize # Current parameter value in list format lstParamVal = self.value.toList() if len(lstParamVal) == 0: return # Keep old value oldParamVal = self.value.clone() indexParam = 0 shiftParam = self.bitSize - 1 if shiftParam < 0: shiftParam = 7 for i in range(bitsToCopy): if indexReg >= len(lstRegVal): break if (lstRegVal[indexReg] >> shiftReg) & 0x01 == 0: mask = ~(1 << shiftParam) lstParamVal[indexParam] &= mask else: mask = 1 << shiftParam lstParamVal[indexParam] |= mask shiftReg -= 1 shiftParam -= 1 # Register byte over? if shiftReg < 0: indexReg += 1 shiftReg = 7 # Parameter byte over? if shiftParam < 0: indexParam += 1 shiftParam = 7 # Did the value change? if not self.value.isEqual(oldParamVal): self.valueChanged = True # Update time stamp self.lastupdate = time.time() def setValue(self, value): """ Set parameter value @param value: New parameter value """ # Convert to SwapValue if value.__class__ is SwapValue: # Incorrect length? if self.value.getLength() != value.getLength(): return self.value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException(value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in ["on", "open", "1", "true", "enabled"]: res = 1 else: res = 0 else: # SwapType.STRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Convert to integer res = int(res) self.value = SwapValue(res, length) # Update current value self.value = SwapValue(res, length) # Update time stamp self.lastupdate = time.time() # Update register value self.register.update() def getValueInAscii(self): """ Return value in ASCII string format @return Value in ASCII format """ if self.type == SwapType.NUMBER: val = self.value.toInteger() # Add units if self.unit is not None: if self.unit.calc is not None: oper = self.unit.calc.replace("${val}", str(val)) try: val = eval("math." + oper) except ValueError as ex: raise SwapException("Math exception for " + oper + ". " + str(ex)) strVal = str(val * self.unit.factor + self.unit.offset) else: strVal = str(val) elif self.type == SwapType.BINARY: strVal = self.value.toAscii() if strVal == "1": strVal = "on" elif strVal == "0": strVal = "off" else: strVal = self.value.toAsciiStr() return strVal def setUnit(self, strunit): """ Set unit for the current parameter @param strunit: new unit in string format """ if self.lstunits is None: raise SwapException("Parameter " + self.name + " does not support units") for unit in self.lstunits: if unit.name == strunit: self.unit = unit return raise SwapException("Unit " + strunit + " not found") def __init__(self, register=None, pType=SwapType.NUMBER, direction=SwapType.INPUT, name="", position="0", size="1", default=None, verif=None, units=None): """ Class constructor @param register: Register containing this parameter @param pType: Type of SWAP endpoint (see SwapDefs.SwapType) @param direction: Input or output (see SwapDefs.SwapType) @param name: Short description about the parameter @param position: Position in bytes.bits within the parent register @param size: Size in bytes.bits @param default: Default value in string format @param verif: Verification string @param units: List of units """ ## Parameter name self.name = name ## Register where the current parameter belongs to self.register = register ## Data type (see SwapDefs.SwapType for more details) self.type = pType ## Direction (see SwapDefs.SwapType for more details) self.direction = direction ## Position (in bytes) of the parameter within the register self.bytePos = 0 ## Position (in bits) after bytePos self.bitPos = 0 # Get true positions dot = position.find('.') if dot > -1: self.bytePos = int(position[:dot]) self.bitPos = int(position[dot+1:]) else: self.bytePos = int(position) ## Size (in bytes) of the parameter value self.byteSize = 1 ## Size in bits of the parameter value after byteSize self.bitSize = 0 # Get true sizes dot = size.find('.') if dot > -1: self.byteSize = int(size[:dot]) self.bitSize = int(size[dot+1:]) else: self.byteSize = int(size) ## Current value self.value = None ## Time stamp of the last update self.lastupdate = None ## List of units self.lstunits = units ## Selected unit self.unit = None if self.lstunits is not None and len(self.lstunits) > 0: self.unit = self.lstunits[0] # Set initial value if default is not None: self.setValue(default) ## Flag that tells us whether this parameter changed its value during the last update or not self.valueChanged = False ## Verification string. This can be a macro or a regular expression self.verif = verif ## Display this parameter from master app self.display = True
def sendSwapCmd(self, value): """ Send SWAP command for the current endpoint @param value: New endpoint value @return Expected SWAP status response to be received from the mote """ # Convert to SwapValue if value.__class__ is SwapValue: swap_value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException(value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in ["on", "open", "1", "true", "enabled"]: res = 1 else: res = 0 else: # SwapType.STRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Take integer part only res = math.modf(res) swap_value = SwapValue(res, length) # Register value in list format lstRegVal = [] lstRegVal[:] = self.register.value.toList() # Build register value indexReg = self.bytePos shiftReg = 7 - self.bitPos # Total bits to be copied from this parameter bitsToCopy = self.byteSize * 8 + self.bitSize # Parameter value in list format lstParamVal = swap_value.toList() indexParam = 0 shiftParam = self.bitSize - 1 if shiftParam < 0: shiftParam = 7 for i in range(bitsToCopy): if (lstParamVal[indexParam] >> shiftParam) & 0x01 == 0: mask = ~(1 << shiftReg) lstRegVal[indexReg] &= mask else: mask = 1 << shiftReg lstRegVal[indexReg] |= mask shiftReg -= 1 shiftParam -= 1 # Register byte over? if shiftReg < 0: indexReg += 1 shiftReg = 7 # Parameter byte over? if shiftParam < 0: indexParam += 1 shiftParam = 7 # Convert to SWapValue newRegVal = SwapValue(lstRegVal) # Send SWAP command return self.register.sendSwapCmd(newRegVal)
class SwapPacket(CcPacket): """ SWAP packet class """ smart_encrypt_pwd = None aes_encrypt_pwd = None def aes_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.aes_encrypt_pwd = password # Data length data_length = len(self.data[4:]) # Data in binary format data = self.data[4:] # Data in binary string format strdata = ''.join([chr(item) for item in self.data[4:]]) # Number of iterations loops = data_length / 16 if data_length % 16: loops += 1 # Create initial nonce init_nonce = [] for i in range(0, 4): for j in range(0, 4): init_nonce.append(self.data[j]) # Password in binary string format strpwd = ''.join([chr(item) for item in password.data]) encryptor = AES.new(strpwd) for i in range(0, loops): str_nonce = ''.join([chr(item) for item in init_nonce]) encrypted_count = encryptor.encrypt(str_nonce) # XOR encypted count against data for j in range(0, 16): k = j + i * 16 if k < data_length: data[k] ^= ord(encrypted_count[j]) else: break # Increment nonce init_nonce[-1] += 1 # Update raw data self.data[4:] = data if not decrypt: # Update packet fields self.function = data[0] & 0x7F if self.extended_address: self.srcAddress = (data[1] << 8) | data[2] self.regAddress = (data[3] << 8) | data[4] self.regId = data[5] if len(data[6:]) > 0: self.value = SwapValue(data[6:]) else: self.regAddress = data[1] self.regId = data[2] if len(data[3:]) > 0: self.value = SwapValue(data[3:]) def smart_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.smart_encrypt_pwd = password # Encryot SwapPacket and CcPacket fields if decrypt: self.nonce ^= password.data[9] self.function ^= password.data[11] ^ self.nonce self.srcAddress ^= password.data[10] ^ self.nonce self.regAddress ^= password.data[8] ^ self.nonce self.regId ^= password.data[7] ^ self.nonce if self.value is not None: pos = 0 newarray = [] for byte in self.value.toList(): byte ^= password.data[pos] ^ self.nonce newarray.append(byte) pos += 1 if pos == 11: pos = 0 self.value = SwapValue(newarray) if not decrypt: self.nonce ^= password.data[9] self._update_ccdata() def send(self, server): """ Overriden send method @param server: SWAP server object to be used for transmission """ self.srcAddress = server.devaddress self.data[1] = self.srcAddress # Update security option according to server's one self.security = server.security self.data[2] |= self.security & 0x0F # Keep copy of the current packet before encryption packet_before_encrypt = copy.copy(self) # Smart encryption enabled? if self.security & 0x02: # Encrypt packet self.smart_encryption(server.password) # AES-128 encryption enabled? elif self.security & 0x04: # Encrypt packet self.aes_encryption(server.password) CcPacket.send(self, server.modem) # Notify event server._eventHandler.swapPacketSent(packet_before_encrypt) def _update_ccdata(self): """ Update ccPacket data bytes """ self.data = [] if self.extended_address: """ self.data[0] = (self.destAddress >> 8) & 0x0F self.data[1] = self.destAddress & 0x0F self.data[5] = (self.srcAddress >> 8) & 0x0F self.data[6] = self.srcAddress & 0x0F self.data[7] = (self.regAddress >> 8) & 0x0F self.data[8] = self.regAddress & 0x0F self.data[9] = self.regId """ self.data.append((self.destAddress >> 8) & 0x0F) self.data.append(self.destAddress & 0x0F) self.data.append((self.hop << 4) | (self.security & 0x0F)) self.data.append(self.nonce) self.data.append(self.function | (self.extended_address * (0x80))) self.data.append((self.srcAddress >> 8) & 0x0F) self.data.append(self.srcAddress & 0x0F) self.data.append((self.regAddress >> 8) & 0x0F) self.data.append(self.regAddress & 0x0F) self.data.append(self.regId) else: """ self.data[0] = self.destAddress self.data[1] = self.srcAddress self.data[5] = self.srcAddress self.data[6] = self.regId """ self.data.append(self.destAddress) self.data.append(self.srcAddress) self.data.append((self.hop << 4) | (self.security & 0x0F)) self.data.append(self.nonce) self.data.append(self.function | (self.extended_address * (0x80))) self.data.append(self.srcAddress) self.data.append(self.regId) """ self.data[2] = (self.hop << 4) | (self.security & 0x0F) self.data[3] = self.nonce self.data[4] = self.function | (self.extended_address * (0x80)) """ if self.value is not None: for item in self.value.toList(): self.data.append(item) def __init__(self, ccPacket=None, destAddr=SwapAddress.BROADCAST_ADDR, hop=0, nonce=0, function=SwapFunction.STATUS, regAddr=0, regId=0, value=None, extended_addr=False): """ Class constructor @param ccPacket: Raw CcPacket where to take the information from @param destAddr: Destination address @param hop: Transmission hop count @param nonce: Security nonce @param function: SWAP function code (see SwapDefs.SwapFunction for more details) @param regAddr: Register address (address of the mote where the register really resides) @param regId: Register ID @param value: Register value """ CcPacket.__init__(self) ## Extended address disabled by default self.extended_address = extended_addr ## Destination address self.destAddress = destAddr ## Source address self.srcAddress = regAddr ## Hop count for repeating purposes self.hop = hop ## Security option self.security = 0 ## Security nonce self.nonce = nonce ## Function code self.function = function ## Register address self.regAddress = regAddr ## Register ID self.regId = regId ## SWAP value self.value = value if ccPacket is not None: if len(ccPacket.data) < 7: raise SwapException("Packet received is too short") # Hop count for repeating purposes self.hop = (ccPacket.data[2] >> 4) & 0x0F # Security option self.security = ccPacket.data[2] & 0x0F # Security nonce self.nonce = ccPacket.data[3] # Superclass attributes ## RSSI byte self.rssi = ccPacket.rssi ## LQI byte self.lqi = ccPacket.lqi ## CcPacket data field self.data = ccPacket.data # Smart Encryption enabled? if self.security & 0x02 and SwapPacket.smart_encrypt_pwd is not None: # Decrypt packet self.smart_encryption(SwapPacket.smart_encrypt_pwd, decrypt=True) # AES-128 Encryption enabled? elif self.security & 0x04 and SwapPacket.aes_encrypt_pwd is not None: # Decrypt packet self.aes_encryption(SwapPacket.aes_encrypt_pwd, decrypt=True) elif self.security & 0x06: return # Function code self.function = ccPacket.data[4] & 0x7F # Extended address indicator self.extended_address = (ccPacket.data[4] & 0x80) != 0 if self.extended_address: # Destination address self.destAddress = (ccPacket.data[0] << 8) | ccPacket.data[1] # Source address self.srcAddress = (ccPacket.data[5] << 8) | ccPacket.data[6] # Register address self.regAddress = (ccPacket.data[7] << 8) | ccPacket.data[8] # Register ID self.regId = ccPacket.data[9] # Register value if len(ccPacket.data) >= 11: self.value = SwapValue(ccPacket.data[10:]) else: # Destination address self.destAddress = ccPacket.data[0] # Source address self.srcAddress = ccPacket.data[1] # Register address self.regAddress = ccPacket.data[5] # Register ID self.regId = ccPacket.data[6] # Register value if len(ccPacket.data) >= 8: self.value = SwapValue(ccPacket.data[7:]) else: self._update_ccdata()
def aes_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.aes_encrypt_pwd = password # Data length data_length = len(self.data[4:]) # Data in binary format data = self.data[4:] # Data in binary string format strdata = ''.join([chr(item) for item in self.data[4:]]) # Number of iterations loops = data_length / 16 if data_length % 16: loops += 1 # Create initial nonce init_nonce = [] for i in range(0,4): for j in range(0,4): init_nonce.append(self.data[j]) # Password in binary string format strpwd = ''.join([chr(item) for item in password.data]) encryptor = AES.new(strpwd) for i in range(0, loops): str_nonce = ''.join([chr(item) for item in init_nonce]) encrypted_count = encryptor.encrypt(str_nonce) # XOR encypted count against data for j in range(0,16): k = j + i*16 if k < data_length: data[k] ^= ord(encrypted_count[j]) else: break # Increment nonce init_nonce[-1] += 1 # Update raw data self.data[4:] = data if not decrypt: # Update packet fields self.function = data[0] & 0x7F; if self.extended_address: self.srcAddress = (data[1] << 8) | data[2] self.regAddress = (data[3] << 8) | data[4] self.regId = data[5] if len(data[6:]) > 0: self.value = SwapValue(data[6:]) else: self.regAddress = data[1] self.regId = data[2] if len(data[3:]) > 0: self.value = SwapValue(data[3:])
class SwapPacket(CcPacket): """ SWAP packet class """ smart_encrypt_pwd = None aes_encrypt_pwd = None def aes_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.aes_encrypt_pwd = password # Data length data_length = len(self.data[4:]) # Data in binary format data = self.data[4:] # Data in binary string format strdata = ''.join([chr(item) for item in self.data[4:]]) # Number of iterations loops = data_length / 16 if data_length % 16: loops += 1 # Create initial nonce init_nonce = [] for i in range(0,4): for j in range(0,4): init_nonce.append(self.data[j]) # Password in binary string format strpwd = ''.join([chr(item) for item in password.data]) encryptor = AES.new(strpwd) for i in range(0, loops): str_nonce = ''.join([chr(item) for item in init_nonce]) encrypted_count = encryptor.encrypt(str_nonce) # XOR encypted count against data for j in range(0,16): k = j + i*16 if k < data_length: data[k] ^= ord(encrypted_count[j]) else: break # Increment nonce init_nonce[-1] += 1 # Update raw data self.data[4:] = data if not decrypt: # Update packet fields self.function = data[0] & 0x7F; if self.extended_address: self.srcAddress = (data[1] << 8) | data[2] self.regAddress = (data[3] << 8) | data[4] self.regId = data[5] if len(data[6:]) > 0: self.value = SwapValue(data[6:]) else: self.regAddress = data[1] self.regId = data[2] if len(data[3:]) > 0: self.value = SwapValue(data[3:]) def smart_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.smart_encrypt_pwd = password # Encryot SwapPacket and CcPacket fields if decrypt: self.nonce ^= password.data[9] self.function ^= password.data[11] ^ self.nonce self.srcAddress ^= password.data[10] ^ self.nonce self.regAddress ^= password.data[8] ^ self.nonce self.regId ^= password.data[7] ^ self.nonce if self.value is not None: pos = 0 newarray = [] for byte in self.value.toList(): byte ^= password.data[pos] ^ self.nonce newarray.append(byte) pos += 1 if pos == 11: pos = 0 self.value = SwapValue(newarray) if not decrypt: self.nonce ^= password.data[9] self._update_ccdata() def send(self, server): """ Overriden send method @param server: SWAP server object to be used for transmission """ self.srcAddress = server.devaddress self.data[1] = self.srcAddress # Update security option according to server's one self.security = server.security self.data[2] |= self.security & 0x0F # Keep copy of the current packet before encryption packet_before_encrypt = copy.copy(self) # Smart encryption enabled? if self.security & 0x02: # Encrypt packet self.smart_encryption(server.password) # AES-128 encryption enabled? elif self.security & 0x04: # Encrypt packet self.aes_encryption(server.password) CcPacket.send(self, server.modem) # Notify event server._eventHandler.swapPacketSent(packet_before_encrypt) def _update_ccdata(self): """ Update ccPacket data bytes """ self.data = [] if self.extended_address: """ self.data[0] = (self.destAddress >> 8) & 0x0F self.data[1] = self.destAddress & 0x0F self.data[5] = (self.srcAddress >> 8) & 0x0F self.data[6] = self.srcAddress & 0x0F self.data[7] = (self.regAddress >> 8) & 0x0F self.data[8] = self.regAddress & 0x0F self.data[9] = self.regId """ self.data.append((self.destAddress >> 8) & 0x0F) self.data.append(self.destAddress & 0x0F) self.data.append((self.hop << 4) | (self.security & 0x0F)) self.data.append(self.nonce) self.data.append(self.function | (self.extended_address * (0x80))) self.data.append((self.srcAddress >> 8) & 0x0F) self.data.append(self.srcAddress & 0x0F) self.data.append((self.regAddress >> 8) & 0x0F) self.data.append(self.regAddress & 0x0F) self.data.append(self.regId) else: """ self.data[0] = self.destAddress self.data[1] = self.srcAddress self.data[5] = self.srcAddress self.data[6] = self.regId """ self.data.append(self.destAddress) self.data.append(self.srcAddress) self.data.append((self.hop << 4) | (self.security & 0x0F)) self.data.append(self.nonce) self.data.append(self.function | (self.extended_address * (0x80))) self.data.append(self.srcAddress) self.data.append(self.regId) """ self.data[2] = (self.hop << 4) | (self.security & 0x0F) self.data[3] = self.nonce self.data[4] = self.function | (self.extended_address * (0x80)) """ if self.value is not None: for item in self.value.toList(): self.data.append(item) def __init__(self, ccPacket=None, destAddr=SwapAddress.BROADCAST_ADDR, hop=0, nonce=0, function=SwapFunction.STATUS, regAddr=0, regId=0, value=None, extended_addr=False): """ Class constructor @param ccPacket: Raw CcPacket where to take the information from @param destAddr: Destination address @param hop: Transmission hop count @param nonce: Security nonce @param function: SWAP function code (see SwapDefs.SwapFunction for more details) @param regAddr: Register address (address of the mote where the register really resides) @param regId: Register ID @param value: Register value """ CcPacket.__init__(self) ## Extended address disabled by default self.extended_address = extended_addr ## Destination address self.destAddress = destAddr ## Source address self.srcAddress = regAddr ## Hop count for repeating purposes self.hop = hop ## Security option self.security = 0 ## Security nonce self.nonce = nonce ## Function code self.function = function ## Register address self.regAddress = regAddr ## Register ID self.regId = regId ## SWAP value self.value = value if ccPacket is not None: if len(ccPacket.data) < 7: raise SwapException("Packet received is too short") # Hop count for repeating purposes self.hop = (ccPacket.data[2] >> 4) & 0x0F # Security option self.security = ccPacket.data[2] & 0x0F # Security nonce self.nonce = ccPacket.data[3] # Superclass attributes ## RSSI byte self.rssi = ccPacket.rssi ## LQI byte self.lqi = ccPacket.lqi ## CcPacket data field self.data = ccPacket.data # Smart Encryption enabled? if self.security & 0x02 and SwapPacket.smart_encrypt_pwd is not None: # Decrypt packet self.smart_encryption(SwapPacket.smart_encrypt_pwd, decrypt=True) # AES-128 Encryption enabled? elif self.security & 0x04 and SwapPacket.aes_encrypt_pwd is not None: # Decrypt packet self.aes_encryption(SwapPacket.aes_encrypt_pwd, decrypt=True) elif self.security & 0x06: return # Function code self.function = ccPacket.data[4] & 0x7F # Extended address indicator self.extended_address = (ccPacket.data[4] & 0x80) != 0 if self.extended_address: # Destination address self.destAddress = (ccPacket.data[0] << 8) | ccPacket.data[1] # Source address self.srcAddress = (ccPacket.data[5] << 8) | ccPacket.data[6] # Register address self.regAddress = (ccPacket.data[7] << 8) | ccPacket.data[8] # Register ID self.regId = ccPacket.data[9] # Register value if len(ccPacket.data) >= 11: self.value = SwapValue(ccPacket.data[10:]) else: # Destination address self.destAddress = ccPacket.data[0] # Source address self.srcAddress = ccPacket.data[1] # Register address self.regAddress = ccPacket.data[5] # Register ID self.regId = ccPacket.data[6] # Register value if len(ccPacket.data) >= 8: self.value = SwapValue(ccPacket.data[7:]) else: self._update_ccdata()
def aes_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.aes_encrypt_pwd = password # Data length data_length = len(self.data[4:]) # Data in binary format data = self.data[4:] # Data in binary string format strdata = ''.join([chr(item) for item in self.data[4:]]) # Number of iterations loops = data_length / 16 if data_length % 16: loops += 1 # Create initial nonce init_nonce = [] for i in range(0, 4): for j in range(0, 4): init_nonce.append(self.data[j]) # Password in binary string format strpwd = ''.join([chr(item) for item in password.data]) encryptor = AES.new(strpwd) for i in range(0, loops): str_nonce = ''.join([chr(item) for item in init_nonce]) encrypted_count = encryptor.encrypt(str_nonce) # XOR encypted count against data for j in range(0, 16): k = j + i * 16 if k < data_length: data[k] ^= ord(encrypted_count[j]) else: break # Increment nonce init_nonce[-1] += 1 # Update raw data self.data[4:] = data if not decrypt: # Update packet fields self.function = data[0] & 0x7F if self.extended_address: self.srcAddress = (data[1] << 8) | data[2] self.regAddress = (data[3] << 8) | data[4] self.regId = data[5] if len(data[6:]) > 0: self.value = SwapValue(data[6:]) else: self.regAddress = data[1] self.regId = data[2] if len(data[3:]) > 0: self.value = SwapValue(data[3:])
class SwapParam: """ Generic SWAP parameter, integrated into a SWAP register """ def getRegAddress(self): """ Return register address of the current parameter @return Register address """ return self.register.getAddress() def getRegId(self): """ Return register ID of the current parameter @return Register ID """ return self.register.id def update(self): """ Update parameter's value, posibly after a change in its parent register """ self.valueChanged = False if self.register is None: raise SwapException("Register not specified for current endpoint") return # Keep old value oldParamVal = self.value.clone() # This is a particular case: endpoint is an ASCII string taking all the # register space if self.type in [SwapType.STRING, SwapType.BSTRING]: self.value = self.register.value else: # Current register value converted to list lstRegVal = self.register.value.toList() # Total bits to be copied indexReg = self.bytePos shiftReg = 7 - self.bitPos bitsToCopy = self.byteSize * 8 + self.bitSize # Current parameter value in list format lstParamVal = self.value.toList() if len(lstParamVal) == 0: return indexParam = 0 shiftParam = self.bitSize - 1 if shiftParam < 0: shiftParam = 7 for i in range(bitsToCopy): if indexReg >= len(lstRegVal): break if (lstRegVal[indexReg] >> shiftReg) & 0x01 == 0: mask = ~(1 << shiftParam) lstParamVal[indexParam] &= mask else: mask = 1 << shiftParam lstParamVal[indexParam] |= mask shiftReg -= 1 shiftParam -= 1 # Register byte over? if shiftReg < 0: indexReg += 1 shiftReg = 7 # Parameter byte over? if shiftParam < 0: indexParam += 1 shiftParam = 7 # Did the value change? if not self.value.isEqual(oldParamVal): self.valueChanged = True # Update time stamp self.lastupdate = time.time() def setValue(self, value): """ Set parameter value @param value: New parameter value """ # Convert to SwapValue if value.__class__ is SwapValue: # Incorrect length? if self.value.getLength() != value.getLength(): return self.value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException(value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in ["on", "open", "1", "true", "enabled"]: res = 1 else: res = 0 else: # SwapType.STRING, SwapType.BSTRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Convert to integer res = int(res) self.value = SwapValue(res, length) # Update current value self.value = SwapValue(res, length) # Update time stamp self.lastupdate = time.time() # Update register value self.register.update() def getValueInAscii(self): """ Return value in ASCII string format @return Value in ASCII format """ if self.type == SwapType.NUMBER: val = self.value.toInteger() # Add units if self.unit is not None: if self.unit.calc is not None: oper = self.unit.calc.replace("${val}", str(val)) try: val = eval("math." + oper) except ValueError as ex: raise SwapException("Math exception for " + oper + ". " + str(ex)) strVal = str(val * self.unit.factor + self.unit.offset) else: strVal = str(val) elif self.type == SwapType.BINARY: strVal = self.value.toAscii() if strVal == "1": strVal = "on" elif strVal == "0": strVal = "off" elif self.type == SwapType.BSTRING: strVal = self.value.toAsciiHex() else: strVal = self.value.toAsciiStr() return strVal def setUnit(self, strunit): """ Set unit for the current parameter @param strunit: new unit in string format """ if self.lstunits is None: raise SwapException("Parameter " + self.name + " does not support units") for unit in self.lstunits: if unit.name == strunit: self.unit = unit return raise SwapException("Unit " + strunit + " not found") def __init__(self, register=None, pType=SwapType.NUMBER, direction=SwapType.INPUT, name="", position="0", size="1", default=None, verif=None, units=None): """ Class constructor @param register: Register containing this parameter @param pType: Type of SWAP endpoint (see SwapDefs.SwapType) @param direction: Input or output (see SwapDefs.SwapType) @param name: Short description about the parameter @param position: Position in bytes.bits within the parent register @param size: Size in bytes.bits @param default: Default value in string format @param verif: Verification string @param units: List of units """ ## Parameter name self.name = name ## Register where the current parameter belongs to self.register = register ## Data type (see SwapDefs.SwapType for more details) self.type = pType ## Direction (see SwapDefs.SwapType for more details) self.direction = direction ## Position (in bytes) of the parameter within the register self.bytePos = 0 ## Position (in bits) after bytePos self.bitPos = 0 # Get true positions dot = position.find('.') if dot > -1: self.bytePos = int(position[:dot]) self.bitPos = int(position[dot+1:]) else: self.bytePos = int(position) ## Size (in bytes) of the parameter value self.byteSize = 1 ## Size in bits of the parameter value after byteSize self.bitSize = 0 # Get true sizes dot = size.find('.') if dot > -1: self.byteSize = int(size[:dot]) self.bitSize = int(size[dot+1:]) else: self.byteSize = int(size) ## Current value self.value = None ## Time stamp of the last update self.lastupdate = None ## List of units self.lstunits = units ## Selected unit self.unit = None if self.lstunits is not None and len(self.lstunits) > 0: self.unit = self.lstunits[0] # Set initial value if default is not None: self.setValue(default) ## Flag that tells us whether this parameter changed its value during the last update or not self.valueChanged = False ## Verification string. This can be a macro or a regular expression self.verif = verif ## Display this parameter from master app self.display = True
def sendSwapCmd(self, value): """ Send SWAP command for the current endpoint @param value: New endpoint value @return Expected SWAP status response to be received from the mote """ # This is a particular case: endpoint is an ASCII string taking all the # register space if self.type == SwapType.STRING and type(value) in [str, unicode]: lstRegVal = value else: # Convert to SwapValue if value.__class__ is SwapValue: swap_value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException(value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in ["on", "open", "1", "true", "enabled"]: res = 1 else: res = 0 else: # SwapType.STRING, SwapType.BSTRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Take integer part only res = math.modf(res) swap_value = SwapValue(res, length) # Register value in list format lstRegVal = [] lstRegVal[:] = self.register.value.toList() # Build register value indexReg = self.bytePos shiftReg = 7 - self.bitPos # Total bits to be copied from this parameter bitsToCopy = self.byteSize * 8 + self.bitSize # Parameter value in list format lstParamVal = swap_value.toList() indexParam = 0 shiftParam = self.bitSize - 1 if shiftParam < 0: shiftParam = 7 for i in range(bitsToCopy): if (lstParamVal[indexParam] >> shiftParam) & 0x01 == 0: mask = ~(1 << shiftReg) lstRegVal[indexReg] &= mask else: mask = 1 << shiftReg lstRegVal[indexReg] |= mask shiftReg -= 1 shiftParam -= 1 # Register byte over? if shiftReg < 0: indexReg += 1 shiftReg = 7 # Parameter byte over? if shiftParam < 0: indexParam += 1 shiftParam = 7 # Convert to SWapValue newRegVal = SwapValue(lstRegVal) # Send SWAP command return self.register.sendSwapCmd(newRegVal)
class SwapPacket(CcPacket): """ SWAP packet class """ smart_encrypt_pwd = None def smart_encryption(self, password, decrypt=False): """ Encrypt/Decrypt packet using the Smart Encryption mechanism @param password: Smart Encryption password @param decrypt: Decrypt packet if True. Encrypt otherwise """ # Update password SwapPacket.smart_encrypt_pwd = password # Encryot SwapPacket and CcPacket fields if decrypt: self.nonce ^= password.data[9] self.function ^= password.data[11] ^ self.nonce self.srcAddress ^= password.data[10] ^ self.nonce self.regAddress ^= password.data[8] ^ self.nonce self.regId ^= password.data[7] ^ self.nonce if self.value is not None: pos = 0 newarray = [] for byte in self.value.toList(): byte ^= password.data[pos] ^ self.nonce newarray.append(byte) pos += 1 if pos == 11: pos = 0 self.value = SwapValue(newarray) if not decrypt: self.nonce ^= password.data[9] self._update_ccdata() def send(self, server): """ Overriden send method @param server: SWAP server object to be used for transmission """ self.srcAddress = server.devaddress self.data[1] = self.srcAddress # Update security option according to server's one self.security = server.security self.data[2] |= self.security & 0x0F # Keep copy of the current packet before encryption packet_before_encrypt = copy.copy(self) # Smart encryption enabled? if self.security & 0x02: # Encrypt packet self.smart_encryption(server.password) CcPacket.send(self, server.modem) # Notify event server._eventHandler.swapPacketSent(packet_before_encrypt) def _update_ccdata(self): """ Update ccPacket data bytes """ self.data = [] self.data.append(self.destAddress) self.data.append(self.srcAddress) self.data.append((self.hop << 4) | (self.security & 0x0F)) self.data.append(self.nonce) self.data.append(self.function) self.data.append(self.regAddress) self.data.append(self.regId) if self.value is not None: for item in self.value.toList(): self.data.append(item) def __init__(self, ccPacket=None, destAddr=SwapAddress.BROADCAST_ADDR, hop=0, nonce=0, function=SwapFunction.STATUS, regAddr=0, regId=0, value=None): """ Class constructor @param ccPacket: Raw CcPacket where to take the information from @param destAddr: Destination address @param hop: Transmission hop count @param nonce: Security nonce @param function: SWAP function code (see SwapDefs.SwapFunction for more details) @param regAddr: Register address (address of the mote where the register really resides) @param regId: Register ID @param value: Register value """ CcPacket.__init__(self) ## Destination address self.destAddress = destAddr ## Source address self.srcAddress = regAddr ## Hop count for repeating purposes self.hop = hop ## Security option self.security = 0 ## Security nonce self.nonce = nonce ## Function code self.function = function ## Register address self.regAddress = regAddr ## Register ID self.regId = regId ## SWAP value self.value = value if ccPacket is not None: if len(ccPacket.data) < 7: raise SwapException("Packet received is too short") # Superclass attributes ## RSSI byte self.rssi = ccPacket.rssi ## LQI byte self.lqi = ccPacket.lqi ## CcPacket data field self.data = ccPacket.data # Destination address self.destAddress = ccPacket.data[0] # Source address self.srcAddress = ccPacket.data[1] # Hop count for repeating purposes self.hop = (ccPacket.data[2] >> 4) & 0x0F # Security option self.security = ccPacket.data[2] & 0x0F # Security nonce self.nonce = ccPacket.data[3] # Function code self.function = ccPacket.data[4] # Register address self.regAddress = ccPacket.data[5] # Register ID self.regId = ccPacket.data[6] if len(ccPacket.data) >= 8: self.value = SwapValue(ccPacket.data[7:]) # Encryption enabled? if self.security & 0x02 and SwapPacket.smart_encrypt_pwd is not None: # Decrypt packet self.smart_encryption(SwapPacket.smart_encrypt_pwd, decrypt=True) else: self._update_ccdata()