fork download
  1. class KeyData:
  2. def __init__(self, seed1, seed2, seed3, password):
  3. self.HdkSeed1 = seed1 & 0xFFFFFFFF
  4. self.HdkSeed2 = seed2 & 0xFFFFFFFF
  5. self.HdkSeed3 = seed3 & 0xFFFFFFFF
  6. self.password = password & 0xFFFFFFFFFFFFFFFF
  7.  
  8. class HLCodeStruct:
  9. def __init__(self):
  10. self.gSeedArray = [0] * 4
  11. self.gPtrArray = [0] * 16
  12. self.gVar1 = 0
  13. self.gVar2 = 0
  14. self.gVar4 = 0
  15.  
  16. def init_g_seeds(key, t):
  17. t.gSeedArray[0] = (key.HdkSeed3 >> 12) & 0xF
  18. t.gSeedArray[1] = (key.HdkSeed3 >> 8) & 0xF
  19. t.gSeedArray[2] = (key.HdkSeed3 >> 4) & 0xF
  20. t.gSeedArray[3] = key.HdkSeed3 & 0xF
  21. for i in range(16):
  22. t.gPtrArray[i] = (((key.HdkSeed1 >> i) & 1) << 1) | ((key.HdkSeed2 >> i) & 1)
  23.  
  24. def init_g_var12(t):
  25. t.gVar1 = 0xF
  26. t.gVar2 = 0
  27. t.gVar4 = 0 # Явно сбрасываем — безопаснее
  28.  
  29. def set_dongle_data(data, t, key):
  30. data &= 0xF
  31. tmp_ptr = t.gPtrArray[t.gVar1]
  32. t.gVar4 = ((t.gVar4 << 4) | tmp_ptr) & 0xFFFF
  33. t.gVar1 ^= data
  34. t.gVar1 ^= t.gVar2
  35. t.gVar1 ^= t.gSeedArray[tmp_ptr]
  36. t.gVar2 = (((t.gVar2 << 2) + tmp_ptr) >> 1) & 0xF
  37.  
  38. def transform0_hw(w0, retw, t, key):
  39. for _ in range(4):
  40. for _ in range(4):
  41. set_dongle_data((w0 & 0xFF) >> 2, t, key)
  42. if w0 & 0x8000:
  43. w0 = ((w0 << 1) | 1) & 0xFFFF
  44. else:
  45. w0 = (w0 << 1) & 0xFFFF
  46. retw >>= 1
  47. nb = (t.gVar4 >> 12) & 1
  48. if nb == 0:
  49. retw |= 0x8000
  50. return retw & 0xFFFF
  51.  
  52. def transform0(w3, w4, t, key):
  53. init_g_var12(t)
  54. ax = w4 ^ transform0_hw(w4, transform0_hw(w3, 0, t, key), t, key)
  55. ax = ((ax >> 15) | (ax << 1)) & 0xFFFF
  56. lo = ax & 0xFF
  57. hi = (ax >> 8) & 0xFF
  58. lo = (lo + hi) & 0xFF
  59. return (hi << 8) | lo
  60.  
  61. def hl_crypt(key, response: bytearray):
  62. t = HLCodeStruct()
  63. init_g_seeds(key, t)
  64.  
  65. w1 = int.from_bytes(response[0:2], 'little')
  66. w2 = int.from_bytes(response[2:4], 'little')
  67. w3 = int.from_bytes(response[4:6], 'little')
  68. w4 = int.from_bytes(response[6:8], 'little')
  69.  
  70. for _ in range(5):
  71. transf = w3 ^ w4 ^ transform0(w3, w4, t, key)
  72. tmp1 = ((transf >> 8) & 0xFF) + (transf & 0xFF)
  73. tmp1 = (tmp1 * 2 + (tmp1 >> 7)) & 0xFF
  74. tmp1 = (tmp1 + 1) & 0xFF
  75. tmp1 = (tmp1 * 2 + (tmp1 >> 7)) & 0xFF
  76.  
  77. tmp2 = (transf & 0xFF) + tmp1
  78. tmp2 = (tmp2 * 2 + (tmp2 >> 7)) & 0xFF
  79. tmp2 = (tmp2 * 2 + (tmp2 >> 7)) & 0xFF
  80.  
  81. transf = ((tmp1 << 8) | tmp2) & 0xFFFF
  82.  
  83. new_w4 = (transf + w4) & 0xFFFF
  84. new_w4 = (((new_w4 + 1) & 0xFF) | (new_w4 & 0xFF00)) & 0xFFFF
  85. new_w4 = ((new_w4 >> 15) | (new_w4 << 1)) & 0xFFFF
  86. new_w4 = ((new_w4 >> 15) | (new_w4 << 1)) & 0xFFFF
  87.  
  88. transf ^= w1
  89. new_w4 ^= w2
  90.  
  91. w1, w2 = w3, w4
  92. w3 ^= transf
  93. w4 ^= new_w4
  94.  
  95. # КРИТИЧЕСКАЯ ПЕРЕСТАНОВКА (как в оригинальном C-коде)
  96. response[0:2] = w3.to_bytes(2, 'little')
  97. response[2:4] = w4.to_bytes(2, 'little')
  98. response[4:6] = w1.to_bytes(2, 'little')
  99. response[6:8] = w2.to_bytes(2, 'little')
  100.  
  101. # Тест
  102. key = KeyData(
  103. seed1=35320,
  104. seed2=12180,
  105. seed3=27464,
  106. password=0x536F667457617265
  107. )
  108.  
  109. buf = bytearray.fromhex("53 6F 66 74 57 61 72 65")
  110. print("IN :", buf.hex())
  111. hl_crypt(key, buf)
  112. print("OUT:", buf.hex())
Success #stdin #stdout 0.13s 14148KB
stdin
Standard input is empty
stdout
IN : 536f667457617265
OUT: 9d99f267e9ac977a