do-crack.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import os, sys
  2. from itertools import product
  3. from multiprocessing import Pool, cpu_count
  4. from binascii import unhexlify
  5. import tqdm
  6. def load_samples(folder):
  7. msgs, crcs = [], []
  8. for fn in os.listdir(folder):
  9. with open(os.path.join(folder,fn),'r') as f:
  10. for L in f:
  11. if '=' not in L: continue
  12. h,c = L.strip().split('=',1)
  13. try:
  14. msgs.append(unhexlify(h))
  15. crcs.append(int(c,16))
  16. except:
  17. pass
  18. return msgs, crcs
  19. def calc_crc8(data, poly, init, xorout, ri, ro):
  20. crc = init
  21. for b in data:
  22. if ri: b = int('{:08b}'.format(b)[::-1],2)
  23. crc ^= b
  24. for _ in range(8):
  25. crc = ((crc << 1) ^ poly) & 0xFF if crc & 0x80 else (crc << 1) & 0xFF
  26. if ro: crc = int('{:08b}'.format(crc)[::-1],2)
  27. return crc ^ xorout
  28. def test_config(args):
  29. poly, init, xorout, ri, ro, msgs, crcs = args
  30. ok = 0
  31. total = len(msgs)
  32. for d, chk in zip(msgs, crcs):
  33. if calc_crc8(d, poly, init, xorout, ri, ro) == chk:
  34. ok += 1
  35. return (poly, init, xorout, ri, ro, ok, total)
  36. def main(folder):
  37. msgs, crcs = load_samples(folder)
  38. if len(msgs) < 2:
  39. sys.exit("Need at least 2 samples")
  40. tasks = [
  41. (poly, init, xorout, ri, ro, msgs, crcs)
  42. for poly in range(256) if (poly & 1 or poly == 1)
  43. for init, xorout, ri, ro in product(range(256), range(256), [False, True], [False, True])
  44. ]
  45. print(f"Wasting ressources on {len(tasks):,} configs using {cpu_count()} cores... yea")
  46. best = []
  47. target = len(msgs)
  48. with Pool() as p:
  49. for poly, init, xorout, ri, ro, ok, total in tqdm.tqdm(p.imap_unordered(test_config, tasks), total=len(tasks)):
  50. if ok == total:
  51. print("FOUND FULL FUCKING MATCH ✅", f"poly=0x{poly:02X}", f"init=0x{init:02X}",
  52. f"xorout=0x{xorout:02X}", f"ri={ri}", f"ro={ro}")
  53. return
  54. # keep top-5 partials
  55. best.append((ok, poly, init, xorout, ri, ro))
  56. best = sorted(best, reverse=True)[:5]
  57. print("\n=== TOP PARTIAL MATCHES ===")
  58. for ok, poly, init, xorout, ri, ro in best:
  59. print(f"{ok}/{total} matches – poly=0x{poly:02X}, init=0x{init:02X}, xorout=0x{xorout:02X}, ri={ri}, ro={ro}")
  60. print("👎 No full match found.")
  61. if __name__ == '__main__':
  62. if len(sys.argv) != 2:
  63. sys.exit(f"Usage: python {sys.argv[0]} <samples_folder>")
  64. main(sys.argv[1])