From 5ee7056389d90f33bd85e1f751605a43b68e9e8f Mon Sep 17 00:00:00 2001 From: Mikhail Yudin Date: Sun, 14 May 2023 15:11:27 +0700 Subject: [PATCH] refactor --- .gitignore | 1 + base.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ crctest.py | 58 ++++++++++++++++++++++++++++++++++++++ encdec.py | 64 ++++++----------------------------------- 4 files changed, 151 insertions(+), 55 deletions(-) create mode 100644 base.py create mode 100644 crctest.py diff --git a/.gitignore b/.gitignore index 3173a6f..4e25c4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ fw/ +__pycache__/ diff --git a/base.py b/base.py new file mode 100644 index 0000000..6a9353a --- /dev/null +++ b/base.py @@ -0,0 +1,83 @@ +from itertools import cycle +from pathlib import Path +from sys import stderr + +from crctest import * + +# Structure of pre-encoded payload +# 8196 | 16 | ... | 2 | +# data | version | data | crc | + +KEY = Path('./key.bin').read_bytes() + +V_OFFSET = 8192 +V_LEN = 16 +CRC_LEN = 2 + + +def eprint(*args, **kwargs): + print(*args, **kwargs, file=stderr) + + +def xor(var, key): + return bytes(a ^ b for a, b in zip(var, cycle(key))) + + +def eprint_crc(crc): + eprint('crc:', ['0x%02x' % x for x in crc], f'{crc[0]*crc[1]}') + + +def make_16byte_version(version): + return bytes([ord(c) for c in version] + [0] * (16 - len(version))) + + +def decrypt(data): + decr = xor(data, KEY) + + v = decr[V_OFFSET:V_OFFSET+V_LEN] + decr_data = decr[:-CRC_LEN] + crc = decr[-CRC_LEN:] + + eprint('version:', v) + eprint_crc(crc) + + return decr_data + + +def encrypt(data, version='2.01.19'): + v = make_16byte_version(version) + data = data[:V_OFFSET] + v + data[V_OFFSET+V_LEN:] + crc = b'\xd9\xab' # here will be some crc + + eprint('version:', v) + eprint_crc(crc) + + return xor(data + crc, KEY) + +def crctest(data): + decr = xor(data, KEY) + + v = decr[V_OFFSET:V_OFFSET+V_LEN] + decr_data = decr[:-CRC_LEN] + crc_dec = decr[-CRC_LEN:] + crc_enc = data[-CRC_LEN:] + + eprint('version:', v) + eprint_crc(crc_dec) + eprint_crc(crc_enc) + + crc1_test = crc_dec[0]*crc_dec[1] + crc2_test = crc_enc[0]*crc_enc[1] + + for crc_f in [crc16_xmodem, crc16_buypass, crc16_ccitt_false, crc16_modbus]: + for d in [data[:-CRC_LEN], decr_data, decr_data[:V_OFFSET]+decr_data[V_OFFSET+V_LEN:-CRC_LEN], data[:V_OFFSET]+data[V_OFFSET+V_LEN:-CRC_LEN]]: + crc_try = crc_f(d) + eprint('try:', crc_try) + if crc_try == crc1_test: + eprint('BINGO: crc1_test', crc_try) + break + if crc_try == crc2_test: + eprint('BINGO: crc2_test', crc_try) + break + + return decr_data diff --git a/crctest.py b/crctest.py new file mode 100644 index 0000000..d4ead0f --- /dev/null +++ b/crctest.py @@ -0,0 +1,58 @@ + +# CRC-16/CCITT-FALSE +def crc16_ccitt_false(data : bytearray): + offset = 0 + length = len(data) + if data is None or offset < 0 or offset > len(data)- 1 and offset+length > len(data): + return 0 + crc = 0xFFFF + for i in range(0, length): + crc ^= data[offset + i] << 8 + for j in range(0,8): + if (crc & 0x8000) > 0: + crc =(crc << 1) ^ 0x1021 + else: + crc = crc << 1 + return crc & 0xFFFF + +# CRC-16/BUYPASS, CRC-16-ANSI, CRC-16-IBM +def crc16_buypass(data: bytes): + xor_in = 0x0000 # initial value + xor_out = 0x0000 # final XOR value + poly = 0x8005 # generator polinom (normal form) + reg = xor_in + for octet in data: + # reflect in + for i in range(8): + topbit = reg & 0x8000 + if octet & (0x80 >> i): + topbit ^= 0x8000 + reg <<= 1 + if topbit: + reg ^= poly + reg &= 0xFFFF + # reflect out + return reg ^ xor_out + +# https://docs.python.org/3/library/binascii.html +import binascii +def crc16_xmodem(data: bytes): + return binascii.crc_hqx(data, 0) + +def crc16_modbus(data : bytearray): + offset = 0 + length = len(data) + if data is None or offset < 0 or offset > len(data) - 1 and offset + length > len(data): + return 0 + crc = 0xFFFF + for i in range(length): + crc ^= data[offset + i] + for j in range(8): + if ((crc & 0x1) == 1): + crc = int((crc / 2)) ^ 40961 + else: + crc = int(crc / 2) + return crc & 0xFFFF + + + diff --git a/encdec.py b/encdec.py index 0b81528..7fe042a 100755 --- a/encdec.py +++ b/encdec.py @@ -1,59 +1,10 @@ #!/usr/bin/env python3 -from itertools import cycle import os from pathlib import Path -from sys import argv, stderr +from sys import argv -# Structure of pre-encoded payload -# 8196 | 16 | ... | 2 | -# data | version | data | crc | - -KEY = Path('./key.bin').read_bytes() - -V_OFFSET = 8192 -V_LEN = 16 -CRC_LEN = 2 - - -def eprint(*args, **kwargs): - print(*args, **kwargs, file=stderr) - - -def xor(var, key): - return bytes(a ^ b for a, b in zip(var, cycle(key))) - - -def eprint_crc(crc): - eprint('crc:', ['0x%02x' % x for x in crc], f'{crc[0]*crc[1]}') - - -def make_16yte_version(version): - return bytes([ord(c) for c in version] + [0] * (16 - len(version))) - - -def decrypt(data): - decr = xor(data, KEY) - - v = decr[V_OFFSET:V_OFFSET+V_LEN] - decr_data = decr[:-CRC_LEN] - crc = decr[-CRC_LEN:] - - eprint('version:', v) - eprint_crc(crc) - - return decr_data - - -def encrypt(data, version='2.01.19'): - v = make_16yte_version(version) - data = data[:V_OFFSET] + v + data[V_OFFSET+V_LEN:] - crc = b'\xd9\xab' # here will be some crc - - eprint('version:', v) - eprint_crc(crc) - - return xor(data + crc, KEY) +from base import crctest, eprint, encrypt, decrypt def usage(info = None): @@ -71,18 +22,21 @@ def main(): encdec = argv[1] fname = argv[2] + file_bytes = Path(fname).read_bytes() + + if encdec == 'crc': + crctest(file_bytes) + return if encdec == 'd': - encrypted = Path(fname).read_bytes() - decrypted = decrypt(encrypted) + decrypted = decrypt(file_bytes) os.write(1, bytes(decrypted)) eprint('Success!') return if encdec == 'e': eprint('WARNING! encoding not working for now, as CRC not valid') - decrypted = Path(fname).read_bytes() - encrypted = encrypt(decrypted) + encrypted = encrypt(file_bytes) os.write(1, bytes(encrypted)) eprint('Success!') return