From a4760b83c15f37263ed7628f513dd08ffd7544db Mon Sep 17 00:00:00 2001 From: itismadness Date: Sat, 8 Jun 2019 10:53:54 -1200 Subject: [PATCH] Fix for logs manually appended to each other --- .gitignore | 4 +- Pipfile | 13 ----- eac_logchecker.py | 116 ++++++++++++++++++++++++++++------------- logs/27.log | Bin 0 -> 59874 bytes setup.cfg | 5 ++ setup.py | 2 + test.py | 46 ---------------- test_eac_logchecker.py | 47 +++++++++++++++++ 8 files changed, 136 insertions(+), 97 deletions(-) delete mode 100644 Pipfile create mode 100644 logs/27.log create mode 100644 setup.cfg delete mode 100755 test.py create mode 100755 test_eac_logchecker.py diff --git a/.gitignore b/.gitignore index f70d73c..c0f11a7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ build/ dist/ *.egg-info/ -.eggs/ \ No newline at end of file +.eggs/ +.pytest_cache/ +__pycache__/ diff --git a/Pipfile b/Pipfile deleted file mode 100644 index bf7f6e4..0000000 --- a/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[dev-packages] - -[packages] -chardet = "*" -pprp = "*" - -[requires] -python_version = "3.6" diff --git a/eac_logchecker.py b/eac_logchecker.py index 4a2c281..892208c 100755 --- a/eac_logchecker.py +++ b/eac_logchecker.py @@ -1,16 +1,27 @@ #!/usr/bin/env python3 import argparse -import contextlib import json from pathlib import Path import re import pprp CHECKSUM_MIN_VERSION = ('V1.0', 'beta', '1') +EAC_KEY = '9378716cf13e4265ae55338e940b376184da389e50647726b35f6f341ee3efd9' -def eac_checksum(text): +class Log: + def __init__(self, text): + self.text = text + self.unsigned_text = self.text + self.version = None + self.modified = False + self.old_checksum = None + self.checksum = None + + +def eac_checksum(log): + text = log.unsigned_text # Ignore newlines text = text.replace('\r', '').replace('\n', '') @@ -19,8 +30,9 @@ def eac_checksum(text): # Setup Rijndael-256 with a 256-bit blocksize cipher = pprp.crypto_3.rijndael( - # Probably SHA256('super secret password') but it doesn't actually matter - key=bytes.fromhex('9378716cf13e4265ae55338e940b376184da389e50647726b35f6f341ee3efd9'), + # Probably SHA256('super secret password') but it doesn't + # actually matter + key=bytes.fromhex(EAC_KEY), block_size=256 // 8 ) @@ -28,7 +40,7 @@ def eac_checksum(text): plaintext = text.encode('utf-16-le') # The IV is all zeroes so we don't have to handle it - signature = b'\x00' * 32 + checksum = b'\x00' * 32 # Process it block-by-block for i in range(0, len(plaintext), 32): @@ -36,39 +48,37 @@ def eac_checksum(text): plaintext_block = plaintext[i:i + 32].ljust(32, b'\x00') # CBC mode (XOR the previous ciphertext block into the plaintext) - cbc_plaintext = bytes(a ^ b for a, b in zip(signature, plaintext_block)) + cbc_plaintext = bytes( + a ^ b for a, b in zip(checksum, plaintext_block) + ) - # New signature is the ciphertext. - signature = cipher.encrypt(cbc_plaintext) + # New checksum is the ciphertext. + checksum = cipher.encrypt(cbc_plaintext) - # Textual signature is just the hex representation - return signature.hex().upper() + # Textual checksum is just the hex representation + log.checksum = checksum.hex().upper() -def extract_info(text): - if len(text) == 0: - return text, None, None +def extract_info(log): + if len(log.text) == 0: + return log - version = None - for line in text.splitlines(): + for line in log.text.splitlines(): if line.startswith('Exact Audio Copy'): - version = tuple(line.split()[3:6]) + log.version = tuple(line.split()[3:6]) elif re.match(r'[a-zA-Z]', line): break - match = re.search('\n\n==== (.*) ([A-Z0-9]+) ====', text) + match = re.search('\n\n==== (.*) ([A-Z0-9]+) ====', log.text) if match: - text, signature_parts = re.split('\n\n==== {}'.format(match.group(1)), text) - signature = signature_parts.split()[0].strip() - else: - signature = None - - return text, version, signature + search = '\n\n==== {}'.format(match.group(1)) + log.unsigned_text, checksum_parts = re.split(search, log.text) + log.old_checksum = checksum_parts.split()[0].strip() -def eac_verify(text): - unsigned_text, version, old_signature = extract_info(text) - return unsigned_text, version, old_signature, eac_checksum(unsigned_text) +def eac_verify(log): + extract_info(log) + eac_checksum(log) def get_logs(data): @@ -85,35 +95,64 @@ def get_logs(data): # Null bytes screw it up if '\x00' in text: text = text[:text.index('\x00')] - + # EAC crashes if there are more than 2^14 bytes in a line if any(len(l) + 1 > 2**13 for l in text.split('\n')): raise RuntimeError('EAC cannot handle lines longer than 2^13 chars') - return [x.strip() for x in re.split(r'[^-]-{60}[^-]', text)] + splits = re.split('(\n\n==== .* [A-Z0-9]+ ====)', text) + logs = [] + for split in splits: + if split.strip() != '': + logs.append(split) + + if len(logs) > 1: + length = len(logs) - 1 if len(logs) % 2 == 1 else len(logs) + return_logs = [] + for i in range(0, length, 2): + log = Log(logs[i] + logs[i+1]) + if i > 0: + (log.text, matches) = re.subn( + r'[^-]-{60}[^-]', + '', + log.text, + 1 + ) + if matches == 0: + log.modified = True + return_logs.append(log) + for i in range(length, len(logs)): + return_logs.append(Log(logs[i])) + else: + return_logs = [Log(logs[0])] + + return return_logs -def check_checksum(arg_file, arg_json): +def check_checksum(arg_file): if not isinstance(arg_file, Path): arg_file = Path(arg_file) - + output = [] if not arg_file.exists(): - if not arg_json: - print('Could not find logfile to examine.') + output.append({ + 'status': 'ERROR', + 'message': 'Could not find logfile to examine.' + }) + return output try: with arg_file.open('rb') as open_file: logs = get_logs(open_file.read()) for log in logs: - data, version, old_signature, actual_signature = eac_verify(log) + eac_verify(log) - if version is None or old_signature is None: + if log.version is None or log.old_checksum is None: message = 'Log entry has no checksum!' status = "NO" - elif old_signature != actual_signature: + elif log.modified or log.old_checksum != log.checksum: message = 'Log entry was modified, checksum incorrect!' status = "BAD" else: @@ -135,7 +174,9 @@ def check_checksum(arg_file, arg_json): def main(): - parser = argparse.ArgumentParser(description='Verifies and resigns EAC logs') + parser = argparse.ArgumentParser( + description='Verifies and resigns EAC logs' + ) parser.add_argument('--json', action='store_true', help='Output as JSON') parser.add_argument('file', type=Path, help='input log file') @@ -145,12 +186,13 @@ def main(): if not args.json: print('Log Integrity Checker (C) 2010 by Andre Wiethoff') print('') - output = check_checksum(args.file, args.json) + output = check_checksum(args.file) if args.json: print(json.dumps(output)) else: for i in range(len(output)): print('{:d}. {:s}'.format(i+1, output[i]['message'])) + if __name__ == '__main__': main() diff --git a/logs/27.log b/logs/27.log new file mode 100644 index 0000000000000000000000000000000000000000..46cff3eae4659b3c8cf385f24dbea310d54d2cf9 GIT binary patch literal 59874 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 Tc((Yi{xklp2F$CkFJAuxpUVbj literal 0 HcmV?d00001 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..a788fc7 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,5 @@ +[aliases] +test=pytest + +[tool:pytest] +addopts = --verbose \ No newline at end of file diff --git a/setup.py b/setup.py index c428424..ea6130a 100644 --- a/setup.py +++ b/setup.py @@ -82,6 +82,8 @@ setup( ] }, install_requires=['pprp'], + setup_requires=['pytest-runner'], + tests_require=['pytest'], license='MIT', classifiers=[ 'Development Status :: 4 - Beta', diff --git a/test.py b/test.py deleted file mode 100755 index d2ffee6..0000000 --- a/test.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env python3 - -from pathlib import Path -import unittest - -import eac_logchecker - -TESTS = [ - (Path('logs/01.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry is fine!', 'status': 'OK'}]), - (Path('logs/02.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]), - (Path('logs/03.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/04.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/05.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry is fine!', 'status': 'OK'}]), - (Path('logs/06.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/07.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/08.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]), - (Path('logs/09.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/10.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/11.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/12.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]), - (Path('logs/13.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]), - (Path('logs/14.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/15.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]), - (Path('logs/16.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]), - (Path('logs/17.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/18.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]), - (Path('logs/19.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/20.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/21.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/22.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/23.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/24.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/25.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry has no checksum!', 'status': 'NO'}]), - (Path('logs/26.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]) -] - -class TestLogchecker(unittest.TestCase): - def test_logs(self): - for log_file, expected in TESTS: - with self.subTest(log=str(log_file)): - actual = eac_logchecker.check_checksum(log_file, True) - self.assertEqual(expected, actual) - - -if __name__ == "__main__": - unittest.main() diff --git a/test_eac_logchecker.py b/test_eac_logchecker.py new file mode 100755 index 0000000..e6d91e2 --- /dev/null +++ b/test_eac_logchecker.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +from pathlib import Path +import pytest + +import eac_logchecker + +LOG_GOOD = {'message': 'Log entry is fine!', 'status': 'OK'} +LOG_NO = {'message': 'Log entry has no checksum!', 'status': 'NO'} +LOG_BAD = { + 'message': 'Log entry was modified, checksum incorrect!', + 'status': 'BAD' +} + + +@pytest.mark.parametrize("log_path, log_statuses", [ + (Path('logs/01.log'), [LOG_GOOD, LOG_GOOD]), + (Path('logs/02.log'), [LOG_GOOD]), + (Path('logs/03.log'), [LOG_NO]), + (Path('logs/04.log'), [LOG_GOOD, LOG_NO]), + (Path('logs/05.log'), [LOG_GOOD, LOG_GOOD]), + (Path('logs/06.log'), [LOG_NO]), + (Path('logs/07.log'), [LOG_NO]), + (Path('logs/08.log'), [LOG_BAD]), + (Path('logs/09.log'), [LOG_NO]), + (Path('logs/10.log'), [LOG_NO]), + (Path('logs/11.log'), [LOG_NO]), + (Path('logs/12.log'), [LOG_GOOD]), + (Path('logs/13.log'), [LOG_GOOD]), + (Path('logs/14.log'), [LOG_NO]), + (Path('logs/15.log'), [LOG_BAD]), + (Path('logs/16.log'), [LOG_BAD]), + (Path('logs/17.log'), [LOG_NO]), + (Path('logs/18.log'), [LOG_GOOD]), + (Path('logs/19.log'), [LOG_NO]), + (Path('logs/20.log'), [LOG_NO]), + (Path('logs/21.log'), [LOG_NO]), + (Path('logs/22.log'), [LOG_NO]), + (Path('logs/23.log'), [LOG_NO]), + (Path('logs/24.log'), [LOG_NO]), + (Path('logs/25.log'), [LOG_GOOD, LOG_NO]), + (Path('logs/26.log'), [LOG_BAD]), + (Path('logs/27.log'), [LOG_GOOD, LOG_BAD, LOG_BAD, LOG_BAD]) +]) +def test_log(log_path, log_statuses): + actual = eac_logchecker.check_checksum(log_path) + assert log_statuses == actual