Files
DeDRM_tools/tests/test_kgenpids.py
T
JMR-devandClaude Opus 4.8 ba96df081f Add pytest suite for both plugins
Add a pytest suite covering the pure logic of the DeDRM and Obok plugins.
Because the plugins normally run inside calibre and use intra-package
imports, tests/dedrm_test_utils.py sets up an import shim (plugin dirs on
sys.path, a minimal calibre stub, and a synthetic `dedrm` package) so the
modules can be imported and exercised standalone.

Coverage:
  - alfcrypto: PC1 and Topaz cipher round-trips, PBKDF2 vs hashlib.
  - kgenpids / kindlepid: PID encoding, bit-field extraction, device-PID
    and serial-PID known vectors, CRC32.
  - mobidedrm: PC1 round-trip, trailing-data sizing, bad-key handling.
  - ineptpdf / ineptepub: nunpack and PKCS7 unpad.
  - topazextract: encoded number/string parsing, plus a regression test
    that a malicious header tag ("../../evil") cannot escape the output
    directory (covers the path-traversal fix).
  - obok: unpad, hash-key table, SafeUnbuffered str/bytes handling.
  - utilities / argv_utils: uStrCmp normalisation, unicode_argv.
  - erdr2pml: deXOR/sanitiseFileName, skipped on Python 3.13+ where the
    module's `cgi` import is unavailable.

Run with `poetry install` then `poetry run pytest`. 36 pass, 2 skip on
Python 3.13+.

Note: this surfaced two dead-code modules that are broken on Python 3
(aescbc's pure-Python AES and kgenpids.decode, neither on a live path,
since the real crypto goes through pycryptodome); left as-is here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:08:03 -05:00

40 lines
1.0 KiB
Python

"""Tests for Kindle PID generation helpers (kgenpids)."""
import dedrm_test_utils as U
kg = U.load("kgenpids")
def test_encode_known_vector():
assert kg.encode(b"\x00\x01\x42\xff\x80", kg.charMap1) == b"6n65tPrMnn"
def test_encode_doubles_length():
data = b"\x10\x20\x30"
assert len(kg.encode(data, kg.charMap1)) == 2 * len(data)
def test_two_bits_from_bit_field():
assert [kg.getTwoBitsFromBitField(b"\x1b\x2c\x3d\x4e", i) for i in range(4)] == [0, 1, 2, 3]
def test_six_bits_from_bit_field():
assert kg.getSixBitsFromBitField(b"\xff\xff\xff\xff", 0) == 63
def test_pid_encryption_table_is_crc32_table():
table = kg.generatePidEncryptionTable()
assert len(table) == 256
assert table[0] == 0
# Standard reflected CRC-32 table entry.
assert table[1] == 0x77073096
def test_generate_device_pid_known_vector():
table = kg.generatePidEncryptionTable()
assert kg.generateDevicePID(table, b"\x12\x34\x56\x78", 4) == b"22I8IQVF"
def test_crc32_known_vector():
assert kg.crc32(b"test") == 4181434640