jeamxn/cisco-pka-to-xml

GitHub: jeamxn/cisco-pka-to-xml

Stars: 0 | Forks: 1

# cisco-pka-to-xml Convert Cisco Packet Tracer activity files (`.pka`) and saved networks (`.pkt`) to readable XML and back. This is a clean-room, MIT-licensed Python implementation of the file format originally documented by [Mirco De Zorzi (`mircodz/pka2xml`)](https://github.com/mircodz/pka2xml). It works against modern Packet Tracer versions (7.x, 8.x, **9.x**) where older XOR-only tools such as [`axcheron/ptexplorer`](https://github.com/axcheron/ptexplorer) fail. ## Table of contents - [How it works](#how-it-works) - [Requirements](#requirements) - [Installation](#installation) - [Usage](#usage) - [Decode a `.pka` to XML](#decode-a-pka-to-xml) - [Encode XML back into a `.pka`](#encode-xml-back-into-a-pka) - [Use as a Python library](#use-as-a-python-library) - [What you get in the XML](#what-you-get-in-the-xml) - [Troubleshooting](#troubleshooting) - [Project layout](#project-layout) - [Contributing](#contributing) - [License](#license) - [Credits](#credits) ## How it works A Packet Tracer file is an XML document that has been put through four reversible stages: 1. **zlib compression** with a 4-byte big-endian uncompressed-length prefix. 2. **Position-keyed XOR**: each byte `b[i]` is XORed with `(length - i) & 0xff`. 3. **Twofish-EAX encryption** with the constant key `0x89` repeated 16 times and IV `0x10` repeated 16 times. 4. **Position-keyed XOR + reversal**: each byte `out[length-1-i] = in[i] ^ ((length - i*length) & 0xff)`. Decoding inverts the pipeline. The Twofish block cipher is the only piece that needs native code; everything else — including the EAX authenticated mode (CMAC + CTR) — is implemented in plain Python in this repository so the only build dependency is a C compiler. The Twofish reference implementation by Niels Ferguson is vendored under [`vendor/twofish/`](./vendor/twofish/) (also MIT-licensed; see [`vendor/twofish/LICENSE`](./vendor/twofish/LICENSE)). ## Requirements - Python 3.8 or newer - A C compiler (any of `cc`, `gcc`, `clang`, or `tcc`) - `patchelf` — only on Linux *and* only if your compiler does not emit a `.note.GNU-stack` section. Modern `gcc`/`clang` do; `tcc` does not. The build script will use `patchelf --clear-execstack` automatically when available. No third-party Python packages are needed. ## Installation git clone https://github.com/jeamxn/cisco-pka-to-xml.git cd cisco-pka-to-xml # Build the Twofish shared library (one-time) python build_libtwofish.py This produces `pka2xml/libtwofish.so` (Linux), `libtwofish.dylib` (macOS), or `libtwofish.dll` (Windows) next to the Python package. If you need to point at an existing build, set the `LIBTWOFISH` environment variable: export LIBTWOFISH=/path/to/libtwofish.so ### Running the tests python tests/test_roundtrip.py The roundtrip test encodes a tiny XML blob and decodes it back. The KAT test runs an official Twofish 128-bit test vector against the native build. ## Usage ### Decode a `.pka` to XML python -m pka2xml decode path/to/activity.pka activity.xml The output is a single XML document. For activity (`.pka`) files it is wrapped in `` and typically contains multiple `` snapshots (initial network, answer network, etc.). Saved networks (`.pkt`) contain a single `` document. ### Encode XML back into a `.pka` python -m pka2xml encode activity.xml rebuilt.pka The output is byte-identical in length category but not byte-identical to the original — zlib's deterministic compression depends on the exact compressor build. Packet Tracer will still open it. ### Use as a Python library from pathlib import Path from pka2xml import decrypt_pka, encrypt_pka xml_bytes = decrypt_pka(Path("activity.pka").read_bytes()) Path("activity.xml").write_bytes(xml_bytes) # round-trip rebuilt = encrypt_pka(xml_bytes) Path("rebuilt.pka").write_bytes(rebuilt) `decrypt_pka` raises `pka2xml.PkaError` if the EAX tag does not match or the inner zlib stream is malformed. That almost always means the file is not a Packet Tracer file or was produced by a very old (pre-6.0) version. ## What you get in the XML A small excerpt from a decoded routing activity: 9.0.0.0810 Router R1 ... interface FastEthernet0/0.10 encapsulation dot1Q 10 ip address 204.200.10.1 255.255.255.0 ... ... Useful tags to grep for once you have the XML: | Tag | Meaning | | ----------------------- | ----------------------------------------------- | | `` / `` | A device node with its display name | | `` | Hardware model (e.g. `2811`, `PC-PT`) | | `` | The IOS `show running-config` of the device | | `` / `` | Interface IP and mask | | `` | Default gateway (on PCs/servers) | | `` | A cable: contains the two endpoints | | `` | Hex-encoded CLI history of the device | ## Troubleshooting | Symptom | Likely cause | | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | | `libtwofish shared library not found` | Run `python build_libtwofish.py` first, or set `LIBTWOFISH=/path/to/libtwofish.so`. | | `cannot enable executable stack as shared object requires` on Linux when loading the lib | Install `patchelf` and rerun the build, or rebuild with a modern `gcc` / `clang`. | | `EAX authentication tag mismatch — file may be corrupt or wrong key` | The input is not a Packet Tracer file produced by version 6.0 or later. | | `zlib decompression failed` | Same as above, or the file was produced by Packet Tracer 5.x (XOR-only — use `ptexplorer`). | | Output XML opens in PT but text is mangled | The XML was edited with a non-UTF-8 editor. Save as UTF-8 without BOM. | ## Project layout . ├── pka2xml/ Python package │ ├── __init__.py Public API: Twofish, decrypt_pka, encrypt_pka, PkaError │ ├── __main__.py CLI entry point (`python -m pka2xml ...`) │ ├── build.py Build script for the native Twofish library │ └── libtwofish.so (Generated) Native Twofish blob cipher ├── vendor/ │ └── twofish/ Niels Ferguson's reference Twofish implementation │ ├── twofish.c │ ├── twofish.h │ └── LICENSE MIT (vendored upstream license) ├── tests/ │ └── test_roundtrip.py KAT + encode/decode roundtrip ├── examples/ │ └── inspect_devices.py Walk the decoded XML and print device + IP info ├── CONTRIBUTING.md ├── LICENSE MIT (this project) └── README.md ### Ways to contribute 1. **File an issue.** If you have a `.pka` that does not decode, open an issue and attach the file (or a redacted excerpt of the hex dump and Packet Tracer version) plus the exact `PkaError` message. 2. **Submit a pull request.** See the workflow below. 3. **Add an example.** Drop a new script under [`examples/`](./examples/) showing a new way to use the library (topology graph rendering, diff between two activities, batch grading, …). 4. **Improve documentation.** README clarity, more troubleshooting entries, language translations under `docs/`. 5. **Help port to Windows / macOS.** The build script accepts `cc`, `gcc`, `clang`, and `tcc`. Reports of what does and does not work on each platform are very welcome. ### Development workflow 1. **Fork the repository** on GitHub and clone your fork. git clone https://github.com//cisco-pka-to-xml.git cd cisco-pka-to-xml git remote add upstream https://github.com/jeamxn/cisco-pka-to-xml.git 2. **Create a feature branch.** Branch names should be short and descriptive. Use the prefixes `feat/`, `fix/`, `docs/`, or `chore/`. git checkout -b feat/windows-build-support 3. **Build and test.** python build_libtwofish.py python tests/test_roundtrip.py 4. **Make your changes.** Keep diffs focused — one PR per topic. Match the style of surrounding code (PEP 8, four-space indent, type hints on new public functions, snake_case names). 5. **Add or update tests.** If you change behavior, add a test under `tests/`. New tests can use stdlib `unittest` or just plain `assert` statements like the existing ones. 6. **Run the full check before pushing.** python build_libtwofish.py python tests/test_roundtrip.py # If you have ruff/black installed locally: # ruff check . # black --check . 7. **Commit with a clear message.** We follow [Conventional Commits](https://www.conventionalcommits.org/) loosely: feat(cli): add --quiet flag to decode subcommand fix(eax): handle empty header buffers on 32-bit Python docs(readme): document LIBTWOFISH env var 8. **Open a pull request** against `main`. Describe the motivation, what changed, and how to reproduce or test. Reference any related issues with `Closes #123`. 9. **Respond to review.** Force-push fixups onto your branch (`git push --force-with-lease`) — we will squash-merge on accept. ### Pull request checklist - [ ] The library still builds with `python build_libtwofish.py` on Linux (and ideally one other OS). - [ ] `python tests/test_roundtrip.py` passes. - [ ] New public functions have docstrings. - [ ] No third-party Python dependencies were added (this project is stdlib-only by design). - [ ] No `.pka` files containing personal information were committed. - [ ] README / CONTRIBUTING were updated if user-visible behavior changed. ### What we will and will not merge We will gladly merge: - Bug fixes, especially for new Packet Tracer versions. - Build/portability improvements (Windows native, BSDs, alpine/musl). - Additional examples and documentation. - Performance improvements that do not change the public API. We will probably not merge: - Anything that adds a heavyweight Python dependency. The Twofish C file is the only native code we want to maintain. - Features that exist solely to bypass Packet Tracer activity grading or licensing. - Code without tests for non-trivial logic changes. ### Reporting security issues Please do **not** open a public issue for a security vulnerability. Instead, open a private security advisory through GitHub's "Security" tab. ### Code of conduct ## License This project is released under the [MIT License](./LICENSE). The vendored Twofish implementation in [`vendor/twofish/`](./vendor/twofish/) is also MIT-licensed; see [`vendor/twofish/LICENSE`](./vendor/twofish/LICENSE).