71 lines
1.9 KiB
Python
Executable File
71 lines
1.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
LONG_KEY = (
|
|
0x6c, 0x1b, 0x99, 0x5f, 0xb9, 0xcd, 0x5f, 0x13,
|
|
0xcb, 0x04, 0x20, 0x0e, 0x5e, 0x1c, 0xa1, 0x0e,
|
|
)
|
|
OTHER_LONG_KEY = (
|
|
0x67, 0xa8, 0xd6, 0x26, 0xb6, 0xdd, 0x45, 0x1b,
|
|
0x32, 0x7e, 0x22, 0x13, 0x15, 0xc2, 0x94, 0x37,
|
|
)
|
|
|
|
|
|
def decode_line(line: bytes, method: int) -> str:
|
|
line = line.rstrip(b"\r\n")
|
|
key = LONG_KEY
|
|
seed = len(line) % 16
|
|
dline = bytearray(len(line))
|
|
for i, c in enumerate(line):
|
|
if i >= 2:
|
|
if line[i - 1] == b'/' and line[i - 2] == b'/':
|
|
key = OTHER_LONG_KEY
|
|
if method == 1:
|
|
if c == ord(b'\t'):
|
|
c = 0x80
|
|
c -= 0x20
|
|
if not (c & 0x80):
|
|
c ^= key[seed]
|
|
c &= 0x7f
|
|
c += 0x20
|
|
|
|
seed += 7
|
|
seed %= 16
|
|
if c == 0x80:
|
|
c = ord(b'\t')
|
|
else:
|
|
if c == ord(b'\t'):
|
|
c = 0x9f
|
|
c -= 0x20
|
|
c ^= key[seed]
|
|
c &= 0x7f
|
|
c += 0x20
|
|
|
|
seed += 7
|
|
seed %= 16
|
|
if c == 0x9f:
|
|
c = ord(b'\t')
|
|
dline[i] = c
|
|
return dline.decode(errors="replace")
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(allow_abbrev=False, description="Decode a Carmageddon encoded file")
|
|
parser.add_argument("file", metavar="FILE", nargs="?", help="input file (default=stdin)")
|
|
parser.add_argument("--method", choices=[1, 2], type=int, default=2, help="decryption method to use")
|
|
args = parser.parse_args()
|
|
|
|
istream = open(args.file, "rb") if args.file else sys.stdin.buffer
|
|
|
|
for line in istream.readlines():
|
|
if line[0] == ord(b'@'):
|
|
dline = decode_line(line[1:], args.method)
|
|
print(dline)
|
|
else:
|
|
print(line.decode())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|