def category(self, value: Category): if value != self.category: self.__category = value if self.category == self.Category.generic: self.checksum = GenericCRC() elif self.category == self.Category.wsp: self.checksum = WSPChecksum() else: raise ValueError("Unknown Category")
def test_enocean_crc_polynomial(self): e = Encoding() msg1 = "aa9a6d201006401009802019e411e8035b" msg2 = "aa9a6d2010000ffdaaf01019e411e8071b" # Remove Preamble + SOF + EOF for CRC calculation msg1 = util.hex2bit("a6d201006401009802019e411e8035") crc1 = util.hex2bit("35") msg2 = util.hex2bit("a6d2010000ffdaaf01019e411e8071") crc2 = util.hex2bit("71") wsp_checker = WSPChecksum() calc_crc1 = wsp_checker.calculate(msg1) calc_crc2 = wsp_checker.calculate(msg2) self.assertTrue(calc_crc1 == crc1) self.assertTrue(calc_crc2 == crc2)
def __init__(self, name: str, start: int, end: int, color_index: int, field_type: FieldType, fuzz_created=False, auto_created=False, data_range_start=0): assert field_type.function == FieldType.Function.CHECKSUM super().__init__(name, start, end, color_index, fuzz_created, auto_created, field_type) self.__category = self.Category.generic self.__data_ranges = [[data_range_start, self.start]] # type: list[list[int,int]] self.checksum = GenericCRC(polynomial=0) # type: GenericCRC or WSPChecksum
def test_enocean_crc_polynomial(self): e = Encoding() msg1 = "aa9a6d201006401009802019e411e8035b" msg2 = "aa9a6d2010000ffdaaf01019e411e8071b" # Remove Preamble + SOF + EOF for CRC calculation msg1 = util.hex2bit("a6d201006401009802019e411e8035") crc1 = util.hex2bit("35") msg2 = util.hex2bit("a6d2010000ffdaaf01019e411e8071") crc2 = util.hex2bit("71") wsp_checker = WSPChecksum() calc_crc1 = wsp_checker.calculate(msg1) calc_crc2 = wsp_checker.calculate(msg2) self.assertTrue(calc_crc1 == crc1) self.assertTrue(calc_crc2 == crc2)
def from_xml(cls, tag: ET.Element, field_types_by_type_id=None): lbl = super().from_xml(tag, field_types_by_type_id) result = cls.from_label(lbl) result.data_ranges = ast.literal_eval(tag.get("data_ranges", "[]")) result.category = cls.Category[tag.get("category", "generic")] crc_tag = tag.find("crc") if crc_tag is not None: result.checksum = GenericCRC.from_xml(crc_tag) wsp_tag = tag.find("wsp_checksum") if wsp_tag is not None: result.checksum = WSPChecksum.from_xml(wsp_tag) return result
def from_xml(cls, tag: ET.Element, field_types_by_caption=None): lbl = super().from_xml(tag, field_types_by_caption) if lbl.field_type is None or lbl.field_type.function != FieldType.Function.CHECKSUM: checksum_field_type = next( (ft for ft in field_types_by_caption.values() if ft.function == FieldType.Function.CHECKSUM), FieldType("checksum", FieldType.Function.CHECKSUM, display_format_index=1)) lbl.field_type = checksum_field_type result = cls.from_label(lbl) result.data_ranges = ast.literal_eval(tag.get("data_ranges", "[]")) result.category = cls.Category[tag.get("category", "generic")] crc_tag = tag.find("crc") if crc_tag is not None: result.checksum = GenericCRC.from_xml(crc_tag) wsp_tag = tag.find("wsp_checksum") if wsp_tag is not None: result.checksum = WSPChecksum.from_xml(wsp_tag) return result
class ChecksumLabel(ProtocolLabel): __slots__ = ("__data_ranges", "checksum", "__category") class Category(Enum): generic = "generic" wsp = "Wireless Short Packet (WSP)" def __init__(self, name: str, start: int, end: int, color_index: int, field_type: FieldType, fuzz_created=False, auto_created=False, data_range_start=0): assert field_type.function == FieldType.Function.CHECKSUM super().__init__(name, start, end, color_index, fuzz_created, auto_created, field_type) self.__category = self.Category.generic self.__data_ranges = [[data_range_start, self.start]] # type: list[list[int,int]] self.checksum = GenericCRC(polynomial=0) # type: GenericCRC or WSPChecksum def calculate_checksum(self, bits: array.array) -> array.array: return self.checksum.calculate(bits) def calculate_checksum_for_message(self, message, use_decoded_bits: bool) -> array.array: data = array.array("B", []) bits = message.decoded_bits if use_decoded_bits else message.plain_bits for data_range in self.data_ranges: data.extend(bits[data_range[0]:data_range[1]]) return self.calculate_checksum(data) @property def data_ranges(self): if self.category == self.Category.wsp: return [[12, -4]] else: return self.__data_ranges @data_ranges.setter def data_ranges(self, value): self.__data_ranges = value @property def is_generic_crc(self): return self.category == self.Category.generic @property def category(self) -> Category: return self.__category @category.setter def category(self, value: Category): if value != self.category: self.__category = value if self.category == self.Category.generic: self.checksum = GenericCRC() elif self.category == self.Category.wsp: self.checksum = WSPChecksum() else: raise ValueError("Unknown Category") def to_label(self, field_type: FieldType) -> ProtocolLabel: result = ProtocolLabel(name=self.name, start=self.start, end=self.end - 1, color_index=self.color_index, field_type=field_type, auto_created=self.auto_created, fuzz_created=self.fuzz_created) result.apply_decoding = self.apply_decoding result.show = self.show result.fuzz_me = self.fuzz_me result.fuzz_values = self.fuzz_values result.display_format_index = self.display_format_index return result @classmethod def from_label(cls, label: ProtocolLabel): result = ChecksumLabel(name=label.name, start=label.start, end=label.end - 1, color_index=label.color_index, field_type=FieldType(label.name, FieldType.Function.CHECKSUM), fuzz_created=label.fuzz_created, auto_created=label.auto_created) result.apply_decoding = label.apply_decoding result.show = label.show result.fuzz_me = label.fuzz_me result.fuzz_values = label.fuzz_values result.display_format_index = label.display_format_index return result @classmethod def from_xml(cls, tag: ET.Element, field_types_by_caption=None): lbl = super().from_xml(tag, field_types_by_caption) if lbl.field_type is None or lbl.field_type.function != FieldType.Function.CHECKSUM: checksum_field_type = next( (ft for ft in field_types_by_caption.values() if ft.function == FieldType.Function.CHECKSUM), FieldType("checksum", FieldType.Function.CHECKSUM, display_format_index=1)) lbl.field_type = checksum_field_type result = cls.from_label(lbl) result.data_ranges = ast.literal_eval(tag.get("data_ranges", "[]")) result.category = cls.Category[tag.get("category", "generic")] crc_tag = tag.find("crc") if crc_tag is not None: result.checksum = GenericCRC.from_xml(crc_tag) wsp_tag = tag.find("wsp_checksum") if wsp_tag is not None: result.checksum = WSPChecksum.from_xml(wsp_tag) return result def to_xml(self): result = super().to_xml() result.tag = "checksum_label" result.attrib.update({"data_ranges": str(self.data_ranges), "category": self.category.name}) result.append(self.checksum.to_xml()) return result
def find(self): result = list() bitvectors_by_n_gram_length = defaultdict(list) for i, bitvector in enumerate(self.bitvectors): bin_num = int(math.ceil(len(bitvector) / self.n_gram_length)) bitvectors_by_n_gram_length[bin_num].append(i) crc = GenericCRC() for length, message_indices in bitvectors_by_n_gram_length.items(): checksums_for_length = [] for index in message_indices: bits = self.bitvectors[index] data_start, data_stop, crc_start, crc_stop = WSPChecksum.search_for_wsp_checksum( bits) if (data_start, data_stop, crc_start, crc_stop) != (0, 0, 0, 0): checksum_range = ChecksumRange(start=crc_start, length=crc_stop - crc_start, data_range_start=data_start, data_range_end=data_stop, crc=WSPChecksum(), score=1 / len(message_indices), field_type="checksum", message_indices={index}) try: present = next(c for c in checksums_for_length if c == checksum_range) present.message_indices.add(index) except StopIteration: checksums_for_length.append(checksum_range) continue crc_object, data_start, data_stop, crc_start, crc_stop = crc.guess_all( bits, ignore_positions=self.already_labeled_cols) if (crc_object, data_start, data_stop, crc_start, crc_stop) != (0, 0, 0, 0, 0): checksum_range = ChecksumRange(start=crc_start, length=crc_stop - crc_start, data_range_start=data_start, data_range_end=data_stop, crc=copy.copy(crc_object), score=1 / len(message_indices), field_type="checksum", message_indices={index}) try: present = next(rng for rng in checksums_for_length if rng == checksum_range) present.message_indices.add(index) continue except StopIteration: pass checksums_for_length.append(checksum_range) matching = awre_util.check_crc_for_messages( message_indices, self.bitvectors, data_start, data_stop, crc_start, crc_stop, *crc_object.get_parameters()) checksum_range.message_indices.update(matching) # Score ranges for rng in checksums_for_length: rng.score = len(rng.message_indices) / len(message_indices) try: result.append(max(checksums_for_length, key=lambda x: x.score)) except ValueError: pass # no checksums found for this length self._debug("Found Checksums", result) try: max_scored = max(filter( lambda x: len(x.message_indices) >= 2 and x.score >= self. minimum_score, result), key=lambda x: x.score) except ValueError: return [] result = list(filter(lambda x: x.crc == max_scored.crc, result)) self._debug("Filtered Checksums", result) return result