mel_protocol_checksum_analyzer.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #!/usr/bin/env python3
  2. """
  3. MEL Protocol Checksum Analyzer
  4. Specifically designed for the MEL protocol hex data
  5. Based on analysis of the provided data patterns.
  6. """
  7. import sys
  8. from typing import List, Tuple
  9. def parse_hex(hex_str: str) -> List[int]:
  10. """Parse hex string to bytes"""
  11. return [int(hex_str[i:i+2], 16) for i in range(0, len(hex_str), 2)]
  12. def analyze_mel_structure(hex_line: str) -> dict:
  13. """Analyze MEL protocol structure"""
  14. bytes_data = parse_hex(hex_line.strip())
  15. return {
  16. 'header': bytes_data[0:4], # 4D454C00
  17. 'length': bytes_data[4], # Packet length
  18. 'flags': bytes_data[5:8], # Type/flags
  19. 'sequence': bytes_data[6], # Sequence number (based on your data)
  20. 'command': bytes_data[8:12], # Command and zone info
  21. 'zone_mask': bytes_data[12:16], # Zone targeting
  22. 'reserved': bytes_data[16:28], # Reserved/padding
  23. 'payload': bytes_data[28:-2], # Actual payload
  24. 'checksum_bytes': bytes_data[-2:], # Last 2 bytes
  25. 'checksum_le': bytes_data[-2] | (bytes_data[-1] << 8), # Little endian
  26. 'checksum_be': (bytes_data[-2] << 8) | bytes_data[-1], # Big endian
  27. 'full_payload': bytes_data[:-2], # Everything except checksum
  28. }
  29. def test_mel_checksums(data: List[int], expected: int) -> List[Tuple[str, int, bool]]:
  30. """Test checksum algorithms specific to MEL protocol"""
  31. results = []
  32. # Test 1: Simple sum of all payload bytes
  33. simple_sum = sum(data) & 0xFFFF
  34. results.append(("Simple Sum", simple_sum, simple_sum == expected))
  35. # Test 2: Sum with initial value (common in embedded protocols)
  36. for init_val in [0x0000, 0x5555, 0xAAAA, 0xFFFF, 0x1234, 0x4321, 0x0001]:
  37. checksum = (sum(data) + init_val) & 0xFFFF
  38. results.append((f"Sum + 0x{init_val:04x}", checksum, checksum == expected))
  39. # Test 3: Two's complement variations
  40. sum_val = sum(data)
  41. twos_comp = (~sum_val + 1) & 0xFFFF
  42. results.append(("Two's Complement", twos_comp, twos_comp == expected))
  43. # Test 4: One's complement
  44. ones_comp = (~sum_val) & 0xFFFF
  45. results.append(("One's Complement", ones_comp, ones_comp == expected))
  46. # Test 5: Subtract from constant
  47. for const in [0xFFFF, 0x10000, 0x8000, 0x7FFF]:
  48. checksum = (const - sum_val) & 0xFFFF
  49. results.append((f"0x{const:04x} - Sum", checksum, checksum == expected))
  50. # Test 6: XOR-based checksums
  51. xor_result = 0
  52. for byte in data:
  53. xor_result ^= byte
  54. results.append(("XOR all bytes", xor_result, xor_result == expected))
  55. # Test 7: Position-weighted sum
  56. pos_sum = sum(i * byte for i, byte in enumerate(data)) & 0xFFFF
  57. results.append(("Position-weighted sum", pos_sum, pos_sum == expected))
  58. # Test 8: Rolling checksum
  59. rolling = 0
  60. for byte in data:
  61. rolling = ((rolling << 1) | (rolling >> 15)) & 0xFFFF
  62. rolling ^= byte
  63. results.append(("Rolling XOR", rolling, rolling == expected))
  64. # Test 9: Modular arithmetic variations
  65. for mod_val in [0x100, 0x101, 0x1FF, 0x200, 0x255, 0x256]:
  66. if mod_val > 0:
  67. checksum = sum(data) % mod_val
  68. results.append((f"Sum mod 0x{mod_val:x}", checksum, checksum == expected))
  69. return results
  70. def analyze_sequence_relationship(filename: str):
  71. """Analyze relationship between sequence numbers and checksums"""
  72. with open(filename, 'r') as f:
  73. lines = [line.strip() for line in f if line.strip()]
  74. print(f"Analyzing sequence-checksum relationship in {filename}")
  75. print("=" * 60)
  76. sequence_data = []
  77. for i, line in enumerate(lines[:20]): # First 20 entries
  78. mel_data = analyze_mel_structure(line)
  79. # Look for the actual sequence field
  80. # Based on your data, it seems to increment in byte 6
  81. actual_sequence = mel_data['sequence']
  82. checksum = mel_data['checksum_le']
  83. sequence_data.append((i, actual_sequence, checksum))
  84. print(f"Entry {i:2d}: seq=0x{actual_sequence:02x} ({actual_sequence:3d}), "
  85. f"checksum=0x{checksum:04x} ({checksum:5d})")
  86. # Look for patterns
  87. print("\nSequence vs Checksum Analysis:")
  88. print("=" * 40)
  89. # Check if checksum changes predictably with sequence
  90. if len(sequence_data) > 1:
  91. for i in range(1, min(10, len(sequence_data))):
  92. seq_diff = sequence_data[i][1] - sequence_data[i-1][1]
  93. check_diff = sequence_data[i][2] - sequence_data[i-1][2]
  94. print(f"Entry {i-1}→{i}: seq_diff={seq_diff:2d}, check_diff={check_diff:4d} (0x{check_diff & 0xFFFF:04x})")
  95. def find_checksum_algorithm(filename: str):
  96. """Main function to find the checksum algorithm"""
  97. with open(filename, 'r') as f:
  98. lines = [line.strip() for line in f if line.strip()]
  99. print(f"MEL Protocol Checksum Analysis")
  100. print(f"File: {filename}")
  101. print(f"Entries: {len(lines)}")
  102. print("=" * 60)
  103. # Analyze first few entries
  104. algorithm_scores = {}
  105. for i, line in enumerate(lines[:10]):
  106. mel_data = analyze_mel_structure(line)
  107. print(f"\nEntry {i}:")
  108. print(f" Hex: {line}")
  109. print(f" Sequence: 0x{mel_data['sequence']:02x}")
  110. print(f" Expected checksum: 0x{mel_data['checksum_le']:04x} (LE)")
  111. print(f" Payload length: {len(mel_data['full_payload'])} bytes")
  112. # Test algorithms
  113. results = test_mel_checksums(mel_data['full_payload'], mel_data['checksum_le'])
  114. for algo_name, result, is_match in results:
  115. if is_match:
  116. print(f" ✓ {algo_name}: 0x{result:04x}")
  117. algorithm_scores[algo_name] = algorithm_scores.get(algo_name, 0) + 1
  118. # Uncomment below to see all results
  119. # else:
  120. # print(f" ✗ {algo_name}: 0x{result:04x}")
  121. # Summary
  122. print(f"\n{'='*60}")
  123. print("ALGORITHM MATCH SUMMARY")
  124. print(f"{'='*60}")
  125. if algorithm_scores:
  126. for algo, score in sorted(algorithm_scores.items(), key=lambda x: x[1], reverse=True):
  127. print(f"{algo}: {score}/10 matches")
  128. best_algo = max(algorithm_scores.items(), key=lambda x: x[1])
  129. if best_algo[1] >= 8: # At least 8/10 matches
  130. print(f"\n🎉 LIKELY ALGORITHM FOUND: {best_algo[0]}")
  131. print(f" Confidence: {best_algo[1]}/10 matches")
  132. else:
  133. print("No consistent algorithm found with standard methods.")
  134. print("This may require custom algorithm development.")
  135. # Analyze sequence relationship
  136. print(f"\n{'='*60}")
  137. analyze_sequence_relationship(filename)
  138. def verify_algorithm(filename: str, algorithm_name: str):
  139. """Verify a specific algorithm against all entries"""
  140. with open(filename, 'r') as f:
  141. lines = [line.strip() for line in f if line.strip()]
  142. print(f"Verifying algorithm '{algorithm_name}' against {len(lines)} entries...")
  143. matches = 0
  144. mismatches = []
  145. for i, line in enumerate(lines):
  146. mel_data = analyze_mel_structure(line)
  147. expected = mel_data['checksum_le']
  148. # Apply the algorithm (you'd implement the specific one here)
  149. if algorithm_name == "Simple Sum":
  150. calculated = sum(mel_data['full_payload']) & 0xFFFF
  151. elif algorithm_name.startswith("Sum + "):
  152. init_val = int(algorithm_name.split("0x")[1], 16)
  153. calculated = (sum(mel_data['full_payload']) + init_val) & 0xFFFF
  154. else:
  155. print(f"Algorithm '{algorithm_name}' not implemented in verify function")
  156. return
  157. if calculated == expected:
  158. matches += 1
  159. else:
  160. mismatches.append((i, expected, calculated))
  161. if len(mismatches) <= 5: # Show first 5 mismatches
  162. print(f" Mismatch at entry {i}: expected 0x{expected:04x}, got 0x{calculated:04x}")
  163. print(f"Results: {matches}/{len(lines)} matches ({100*matches/len(lines):.1f}%)")
  164. if matches == len(lines):
  165. print("🎉 PERFECT MATCH! Algorithm verified.")
  166. elif matches > len(lines) * 0.9:
  167. print("⚠️ Very close match. May need minor adjustment.")
  168. else:
  169. print("❌ Algorithm doesn't work consistently.")
  170. def main():
  171. if len(sys.argv) < 2:
  172. print("Usage:")
  173. print(" python mel_checksum_analyzer.py <hex_file> # Find algorithm")
  174. print(" python mel_checksum_analyzer.py <hex_file> verify <algorithm> # Verify algorithm")
  175. sys.exit(1)
  176. filename = sys.argv[1]
  177. if len(sys.argv) >= 4 and sys.argv[2] == "verify":
  178. algorithm = sys.argv[3]
  179. verify_algorithm(filename, algorithm)
  180. else:
  181. find_checksum_algorithm(filename)
  182. if __name__ == "__main__":
  183. main()