Skip to content

Instantly share code, notes, and snippets.

@khang06
Last active May 31, 2024 12:46
Show Gist options
  • Save khang06/dde2c333614b21ac6350f38c50662c45 to your computer and use it in GitHub Desktop.
Save khang06/dde2c333614b21ac6350f38c50662c45 to your computer and use it in GitHub Desktop.
PublicProfile.save encryption/decryption tool for Bloons TD Battles 2 1.0.4
import binascii
import sys
import string
import os
# the checksum algorithm operates on signed integers
def arsh32(n, b):
n = n & 0xFFFFFFFFF
n = (n ^ 0x80000000) - 0x80000000
return (n >> b) & 0xFFFFFFFF
def checksum(data):
ret = 0
for i in range(len(data)):
temp = (ret ^ data[i]) & 0xFF
if (temp & 1) != 0:
temp = arsh32(temp ^ 0xDB710641, 1)
else:
temp = arsh32(temp, 1)
for j in range(7):
if j != 0:
temp = arsh32(temp, 1)
if (temp & 1) != 0:
temp ^= 0xDB710641
ret = arsh32(temp, 1) ^ arsh32(ret, 8) & 0xFFFFFF
return ret
# no scanf in python
def scan_hex(file):
out = ""
while True:
try:
char = file.read(1).decode("utf-8")
if char in string.hexdigits:
out += char
else:
break
except UnicodeDecodeError:
break
file.seek(-1, os.SEEK_CUR)
return int(out, 16)
def stephen_encrypt(data):
for i in range(len(data)):
data[i] += i % 6 + 21
def stephen_decrypt(data):
for i in range(len(data)):
data[i] += 6 * (i // 6) - i - 21
def decrypt_save(in_file, out_file):
with open(in_file, "rb") as save:
magic = save.read(6)
if magic != b"DGDATA":
print("wrong magic")
return
stored_crc = scan_hex(save)
print(f"stored checksum: {hex(stored_crc)}")
data = bytearray(save.read())
stephen_decrypt(data)
calced_crc = checksum(data)
if stored_crc == calced_crc:
print(f"checksum OK")
else:
print(f"checksum mismatch! (calculated: {hex(calced_crc)})")
with open(out_file, "wb") as dec:
dec.write(data)
def encrypt_save(in_file, out_file):
with open(in_file, "rb") as dec:
data = bytearray(dec.read())
calced_crc = checksum(data)
stephen_encrypt(data)
data = bytearray(f"DGDATA{calced_crc:08x}", encoding="utf8") + data
with open(out_file, "wb") as save:
save.write(data)
if __name__ == "__main__":
if len(sys.argv) != 4:
print(f"usage: {sys.argv[0]} [decrypt/encrypt] [in] [out]")
sys.exit(1)
if sys.argv[1] == "decrypt":
decrypt_save(sys.argv[2], sys.argv[3])
elif sys.argv[1] == "encrypt":
encrypt_save(sys.argv[2], sys.argv[3])
else:
print("invalid mode!")
@Otheruser325
Copy link

Ok

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment