{"owner":"RfidResearchGroup","repo":"proxmark3","hasSkills":true,"totalSkillsCount":15,"totalTokensCount":15536,"categories":["plugin-manifest","root-instruction","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["tools/ePassport/README.md","AGENTS.md","tools/hitag2crack/README.md","tools/deprecated-hid-flasher/flasher/README.md","tools/kgh/README.md","tools/hitag2crack/crack3/README.md","tools/hitag2crack/crack5/README.md","tools/hitag2crack/crack4/README.md","tools/hitag2crack/crack5gpu_disabled/README.md","tools/mfc/card_reader/mf_nonce_brute_examples.md","tools/hitag2crack/crack5opencl/README.md","tools/hitag2crack/crack2/README.md","tools/mfc/card_reader/mfkey_examples.md","tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md","tools/hitag2crack/common/OpenCL-Headers/README.md"],"skills":{"tools/ePassport/README.md":"# ePassport\n\nAn ePassport (eMRTD) viewer: reads a passport chip through the Proxmark3 and\nrenders it as a passport data page.\n\nEverything runs **offline**. No telemetry, no cloud OCR, no network calls of\nany kind — every font and asset is bundled.\n\n```\n./ePassport.py                                   # normal use\n./ePassport.py --dump DIR                       # open a saved dump, no hardware\n./ePassport.py --dry-run pm3.log --dump DIR     # replay a session you recorded\n./ePassport.py --help\n```\n\n`ePassport.py` is a plain launcher script — run it directly (it has a shebang) or with `python3`, from anywhere, by path or\nfrom a symlink; there is nothing to install and no `PYTHONPATH` to set. If a\ndependency is missing it says which one, which interpreter it used, and the\nexact command to fix it.\n\nIt needs an interpreter that has the requirements. With a virtualenv, either\nactivate it first or point at it directly:\n\n```bash\n/path/to/venv/bin/python ./ePassport.py\n```\n\n---\n\n## Install\n\n```bash\npython3 -m pip install -r requirements.txt\n```\n\nKivy is required. Everything else is optional and the app degrades with a\nmessage telling you what to install:\n\n| Missing | What stops working |\n|---|---|\n| `opencv-python-headless` | the Scan screen (camera) |\n| `pytesseract` + the `tesseract-ocr` binary | MRZ OCR — manual entry still works |\n| `Pillow` / `glymur` | portrait decoding (DG2 is usually JPEG2000) |\n| `asn1crypto` / `cryptography` | EF_SOD inspection and the DG hash table |\n\nFor the best OCR accuracy install the OCR-B or `mrz` traineddata; the app picks\nit up automatically and falls back to `eng` with a character whitelist.\n\n`sudo apt install xclip` enables Kivy's cut-buffer support. The app filters\nthe noisy `[CRITICAL] [Cutbuffer]` complaint either way; nothing depends on it.\n\n## Relationship to proxmark3\n\nThis app **does not modify the proxmark3 tree**. The only coupling is the `pm3`\nCLI, invoked in one-shot command mode:\n\n```\npm3 -c \"hf emrtd dump -n <DOCNUM> -d <YYMMDD> -e <YYMMDD> --dir <outdir>\"\npm3 -c \"hf emrtd info --dir <existing dump>\"     # offline mode\n```\n\nThe binary is located via `$PM3_BIN` → the configured path → `PATH` → `~/pm3/pm3`\n→ the `./pm3` wrapper of an enclosing proxmark3 source tree.\n\nThe country-name table in `emrtd/countries.py` is **generated** from the\nproxmark3 client's own ISO-3166 table (`fdxbCountryMapping` in\n`client/src/cmdlffdxb.c`). Regenerate it with:\n\n```bash\npython3 tools_gen_countries.py ../../client/src/cmdlffdxb.c\n```\n\n### Authentication\n\n| You have | Enter | What runs |\n|---|---|---|\n| The MRZ | document number + both dates, or line 2 | PACE with the MRZ, falling back to BAC |\n| The CAN | the number printed on the data page | `--can` (PACE only) |\n\nThe **CAN** is the short number printed on the data page — usually 6 digits.\nIt is a PACE password, so it is mutually exclusive with the MRZ, and BAC can\nnever use it. The Authentication dropdown forces `--pace` or `--bac` when you\nwant to test one path; leave it on Automatic otherwise.\n\nWrong CANs are counted by the chip and the password will eventually block, so\nthat failure is called out separately from a wrong MRZ.\n\n### Two things worth knowing about `hf emrtd`\n\n- **All three of `-n/-d/-e` must be supplied**, or the client silently drops to\n  no-BAC mode and fails on any protected passport. The app refuses a partial\n  triple rather than passing it on.\n- **The `pm3` wrapper blocks forever** waiting for a device when none is\n  attached. The app watches for that line and reports \"No Proxmark3 found\"\n  immediately instead of sitting on the timeout.\n\n## Using it\n\n1. **Scan** the MRZ with a camera, or **type** the three values. A full 44-char\n   MRZ line 2 takes precedence and is passed as `-m`, which avoids\n   field-splitting mistakes.\n2. **Read** — pm3 runs on a worker thread and streams into the LOG tab, with a\n   determinate progress bar and a Cancel that actually kills the process.\n3. The dump is parsed from the **binaries** (BER-TLV), never scraped from\n   `hf emrtd info` stdout, and rendered as a data page.\n\nTabs across the top: `DATA PAGE` · `PERSONAL` (DG11) · `ISSUER` (DG12) ·\n`SECURITY` (SOD/DG14/DG15) · `FILES` · `LOG`.\n\n### Output\n\nThe app is quiet by default. Kivy 2.3 takes its log level from\n`~/.kivy/config.ini`, which is shared with every other Kivy app on the machine,\nso rather than rewrite that the app drops Kivy's console handler and installs\nits own for warnings and above. pytesseract (which logs a full tesseract\ncommand line per frame), OpenCV and its V4L2 backend are quietened the same\nway. `-v` puts all of it back.\n\n### Resizing\n\nThe page is laid out **once** at a fixed resolution and then drawn scaled, so a\nresize costs a matrix multiply rather than a full re-flow. Re-flowing it on\nevery resize event re-rendered every label and regenerated the security print\nseveral times a frame, which made dragging a window edge crawl and the contents\njitter as text reflowed under the cursor.\n\nMeasured over twenty resize steps:\n\n| | Before | After |\n|---|---|---|\n| Page widget redraws per step | 21 | 0 |\n| Label re-renders per step | 65 | 11 (window chrome only) |\n| Time in text rendering | 182 ms | 10 ms |\n\nTwo supporting fixes: redraws are coalesced onto a `Clock` trigger so `pos` and\n`size` changing separately cannot cause three redraws in one frame, and MRZ\nglyphs are cached per (character, size) — an MRZ is ~90 characters drawn from\nan alphabet of 37, so it was building ninety textures to show at most\nthirty-seven distinct ones.\n\n### Why a document may not fill the window\n\nBoth formats are always scaled as large as they fit without distorting, so\nneither is ever \"shrunk\" — but a document and a window are different shapes,\nand only one of the two dimensions can fill. Whichever document is closer to\nthe window's shape uses more of it:\n\n| Window content shape | Passport (1.42) | Card (1.59) |\n|---|---|---|\n| 1.61 (wide) | 88% wide, 100% tall | 99% wide, 100% tall |\n| 1.42 (the default) | **100% wide, 100% tall** | 100% wide, 90% tall |\n| 2.59 (very wide) | 55% wide, 100% tall | 61% wide, 100% tall |\n\nThe default window is sized so its **content area comes out at the reference\ndocument's own 125:88**, so a passport fills it exactly on first run. Stretch\nthe window wide and both documents will letterbox at the sides; that is the\nshape mismatch, not the app giving up on the space.\n\n### Small windows\n\nThe minimum window is 760x520 and the app remembers the size you leave it at.\nEverything is built to survive that:\n\n- the passport page scales as a unit and keeps its aspect;\n- the tab strip shares its width rather than claiming fixed slots;\n- the FILES table uses proportional columns, so the state column does not fall\n  off the edge;\n- the hex viewer fits **16, 8 or 4 bytes per row** to whatever width the pane\n  has, because a hex dump must not wrap.\n\n### Speed\n\nAn MRZ scan settles in roughly a second. What that took:\n\n| Change | Effect |\n|---|---|\n| Cheap pre-gate before OCR (`looks_like_text`) | a badly framed strip costs ~0.3 ms instead of ~400 ms |\n| Skip frames already processed | no repeat OCR of an identical frame |\n| Pace the loop instead of adding to it | the interval no longer stacks on top of the work |\n| Cache the language lookup | it shelled out to tesseract every frame |\n| Stop escalating variants with no signal | 2 passes instead of 3 on hopeless frames |\n| Remember the last winning variant | dim lighting costs 1 pass, not 3 |\n\nMeasured on a live camera: mean OCR pass 381 ms → 163 ms, time to acceptance\n3.1 s → 1.3 s, with accuracy unchanged on the synthetic bench.\n\nThe gate runs *after* deskew — it measures horizontal bands of ink, and tilted\ntext smears those bands together.\n\nAn in-process binding (`tesserocr`) is ~3× faster per call than re-launching\nthe tesseract binary, and was tried. It is **not** used: the PyPI wheel bundles\nits own leptonica, and pairing that with a system `tessdata` directory hung\nindefinitely mid-recognition. A backend that can wedge the OCR thread is worse\nthan a slower one.\n\n### Cameras\n\nThe Scan screen enumerates capture devices by name from\n`/sys/class/video4linux` — without opening them, because opening a device is\ndisruptive if something else is using it.\n\n- **No camera**: the screen says so and offers **Rescan for devices**. Manual\n  entry is always available and works just as well.\n- **One or more**: a dropdown lists them by name (`0: IPEVO Ziggi-HD Plus`).\n  The choice is remembered.\n\nLinux commonly exposes several `/dev/videoN` nodes for one physical camera,\nonly one of which delivers frames — `isOpened()` returns true for the others.\nThe app therefore treats a successful *read* as the test, and falls back to a\nneighbouring index automatically. **Rescan** probes every device to label the\ndead ones `(no frames)`; it stops the preview first so the probe and the\ncapture thread do not fight over the device.\n\nOnly line 2 is needed for BAC, so the scan accepts a lone line 2 when its five\ncheck digits — composite included — all pass.\n\n### What a \"valid\" MRZ scan does and does not prove\n\nA scan is accepted only when every check digit validates **and** two\nconsecutive frames agree. That still does not prove the document number is\nright. The 7-3-1 checksum is taken modulo 10 and its weights are coprime with\n10, so swapping a character for one whose value differs by a multiple of 10\nleaves every check digit — composite included — unchanged. The blind pairs are\n`L`/`1`, `S`/`8`, `G`/`6`, `Z`/`5`, `I`/`8`, `D`/`3` … which are exactly the\nswaps OCR is most likely to make.\n\nThat is why a scan **fills the entry form and stops** rather than starting a\nread, and why the form flags the document number for a second look. If BAC\nthen fails, the document number is the first thing to check.\n\n(Confusions that are *not* blind, such as `O` read as `0` in a country code,\nare repaired automatically by position before validation.)\n\n### Drawing the page\n\nA TD1 is an ID-1 card (85.6 x 54 mm), not a small passport data page\n(125 x 88 mm), and its three-line MRZ takes about a quarter of its height\nagainst an eighth for a passport's two lines. The page is drawn at whichever\nshape the document really is.\n\n**Two scale modes**, because you cannot have both at once. OCR-B is a fixed\n2.54 mm pitch on every format, but a character is 2.97% of a card's width and\nonly 2.03% of a passport's — so a card's MRZ is inherently half again as large\nrelative to its own document:\n\n| Mode | What it gives you | What it costs |\n|---|---|---|\n| **Fit window** (default) | every document fills the window | a card's MRZ prints ~1.5x a passport's on screen |\n| **True size** | MRZ print identical across formats, as in the hand | a card is drawn two thirds the width, leaving margins |\n\nOpening a dump re-fits the page for whatever format it turns out to be, so the\nbutton is a preference you set once, not something to press after every load.\nThe toolbar button swaps them and the choice is remembered. It is labelled\nwith the **action**, like the chrome button beside it: reading \"Fit window\"\nmeans clicking will fit the window, so you are currently at true size. A\npassport looks identical either way; only formats smaller than the reference\npage differ.\n\nWithin the band, the MRZ block is sized to fit in **both** directions — the\nsmaller of the width- and height-derived sizes wins, and a block that does not\nfill the width is centred. Fitting the width alone pushed a card's MRZ out over\nthe fields above it; leaving a full line of air between rows then shrank it\nuntil it no longer reached the margins.\n\nThe **portrait** is sized from the page width and the real 35 x 45 photo shape,\ncapped against the space above the band — a fraction of page height alone made\nit swallow a short card. The frame keeps the photo aspect whichever constraint\nbinds, so an image never sits letterboxed in white bars.\n\nThe guilloche is generated procedurally (superimposed hypotrochoids at low\nalpha) — nothing is traced from a real document's security print. It is clipped\nto the printed frame **geometrically**, with a Liang-Barsky segment clip, not\nwith a stencil: this widget can sit inside another `StencilView`, and Kivy's\nnested stencils do not intersect, so an inner stencil silently stops clipping\nanything. That bug had the pattern spilling past the page edge onto the\nwindow background.\n\nText over the pattern measures about 15:1 contrast, well clear of the 4.5:1\nfloor.\n\n### Fields that may not be there\n\nDG11 and DG12 are optional and plenty of real passports omit them entirely —\nplace of birth, date of issue and issuing authority are printed on the page but\nnever written to the chip. Those fields say **\"not on chip\"** rather than\nshowing an empty value, so a missing data group is not mistaken for a parse\nfailure.\n\nThe **personal number** is recovered from the MRZ optional-data field when\nDG11 is absent — several states, Sweden among them, put the national identity\nnumber there. The field's caption says `PERSONAL No. (FROM MRZ)` when it came\nfrom that fallback.\n\n### What the SECURITY tab does and does not check\n\nIt hashes each dumped data group and compares against the hash table inside\nEF_SOD, marking every DG **match / MISMATCH / not checked**. It does **not**\nvalidate the signer certificate chain — that needs the issuing country's CSCA\ncertificate, which the app deliberately does not fetch.\n\n## Where your reads go\n\nEvery read writes to:\n\n```\n~/.local/share/ePassport/dumps/<UTC-timestamp>/\n```\n\ncreated `0700`. The app was previously called `pm3-passport`; if a directory\nof that name exists it is moved to the new one on first run, so earlier reads\nare carried across rather than orphaned. You do not need to remember that: **Dumps…** in the toolbar\nlists every read with its timestamp and contents. From there you can open one,\ndelete one with the bin button, open the folder in your file manager, or clear\nout the empty directories left behind by reads that failed. The path is also in\nthe status bar (click it) and in the log at the start of every read.\n\nEvery read also leaves `pm3.log` in its directory: the client output for that\nrun, which is the only record of why a read that dumped nothing gave up. It\nholds what the LOG pane showed and not the MRZ or CAN you typed, and it does\nnot count as a file when the app decides whether a read produced anything.\n\nDeleting always asks first, and says what it is about to destroy — a dump holds\na real portrait and a real MRZ.\n\n**Opening a dump from elsewhere** (a colleague's, or the generated samples):\n**Dumps… → Samples…** goes straight to `./samples`, and **Browse…** opens a\npicker with one-click jumps to **Recent**, **Dumps**, **Samples**, **Working\ndir** and **Home**, plus a path box you can type or paste into.\n\nThe picker reopens **beside the last dump you loaded**, so picking a second\ndump next to the first does not mean navigating there again. Shortcuts that do\nnot exist are not shown — `Samples` only appears once you have generated them —\nand duplicates collapse, so `Recent` and `Samples` do not both appear when they\nare the same folder.\n\n## Your data\n\n- Dumps are `0700` and there is a **Delete dump** button.\n- MRZ values and document numbers are never written outside that directory.\n- \"Remember\" on the entry screen defaults to **off** — those values are live\n  credential material.\n- The app is strictly read-only: it displays what the chip returns, and no\n  field is editable.\n\n## Development\n\n```bash\nmake test              # 297 tests, no hardware needed\nmake samples           # generate the fabricated dumps into ./samples\nmake clean             # drop __pycache__ and the test cache\nmake distclean         # the above, plus the generated samples\nmake format            # reformat with black\nmake help              # the rest\n```\n\nThe proxmark3 root `Makefile` recurses in here too, following the same pattern\nit uses for `hitag2crack`:\n\n```bash\nmake ePassport/clean     # from the repository root\nmake ePassport/test\nmake ePassport/help\n```\n\nePassport is deliberately **not** in the root `TARGETS`, so a plain `make` or\n`make clean` at the top level does not touch it — it builds nothing and is not\npart of the firmware or client build.\n\n`make` shells out to `python3`; if your dependencies live in a virtualenv,\npoint it at that interpreter:\n\n```bash\nmake test PYTHON=/path/to/venv/bin/python\n```\n\nThe same without `make`:\n\n```bash\npython3 -m pytest tests/ -q\npython3 tools_make_sample.py [DIR]              # generate the sample dumps\npython3 -m epassport.emrtd samples/td3_utopia   # headless: parse and print\npython3 -m black epassport tests tools_*.py\n```\n\n### Nothing derived from a document is checked in\n\nThis tree carries **no dumps, no logs and no images**. A dump holds a live\nportrait and MRZ, and a screenshot of one is just as identifying — so none of\nit belongs in version control, not even the fabricated kind, and `.gitignore`\nrefuses the file types outright.\n\nWhat you need instead is generated:\n\n```bash\npython3 tools_make_sample.py [DIR]      # fabricated dumps, default ./samples\n```\n\nThey are documents of the fictional ICAO specimen state \"Utopia\": no real\npersonal data, no real security print. `td3_utopia` carries a genuinely signed\nEF_SOD, `td3_utopia_tampered` is the same document with DG2 swapped after\nsigning so the SECURITY tab has a MISMATCH to show, and `td1_utopia_idcard` is\na TD1 card with no DG11/DG12 or SOD.\n\nThe tests never touch that directory: `tests/conftest.py` builds its own copy\ninto a temporary directory, and the recorded pm3 sessions used by the\n`--dry-run` tests are inline in `tests/test_pm3_client.py`.\n\nTo replay a real session, record it yourself:\n\n```bash\npm3 -c \"hf emrtd dump -n ... -d ... -e ...\" | tee pm3.log\n```\n\n### Layout\n\n```\nMakefile             run / test / format / clean\nePassport.py         the launcher; everything below is the implementation\nepassport/\n  app.py               app, screens, worker threads\n  __main__.py          shim so `python3 -m epassport` still works\n  config.py            paths, settings, 0700 data dir\n  pm3/client.py        subprocess, streaming, cancel, timeout\n  pm3/errors.py        typed failures + plain-English remedies\n  emrtd/tlv.py         BER-TLV reader\n  emrtd/mrz.py         TD1/TD2/TD3, check digits, date window\n  emrtd/dg.py          per-DG decoders -> PassportRecord\n  emrtd/sod.py         optional CMS/SOD inspection\n  emrtd/images.py      JPEG/JP2 carving out of CBEFF blobs\n  emrtd/model.py       PassportRecord: the single UI-facing object\n  ocr/                 camera thread, OCR pipeline, accept rule\n  ui/                  Kivy widgets and .kv files\n```\n\n**Threading contract:** the pm3 subprocess, file parsing, image decoding and\nOCR all run off the main thread; UI mutation happens only via\n`Clock.schedule_once`. The app never freezes while a dump runs.\n\n**Single source of truth:** every parser produces one `PassportRecord`, and the\nUI binds only to that — which is why \"open saved dump\" and \"read from card\" are\nthe same rendering path.\n","AGENTS.md":"# AGENTS.md\n\nInstructions for AI coding agents (and humans using one) proposing pull requests\nto this repository. This complements `README.md` and `Maintainers.md`; when in\ndoubt, those human-facing docs win.\n\n## Repo shape (quick map)\n\n- `bootrom/`, `armsrc/` — ARM firmware for the device (Proxmark3\n  hardware targets), buildable via **either** the top-level\n  `Makefile` **or** their respective `CMakeLists.txt`. Keep both build definitions in sync.\n- `client/` — host-side client, buildable via **either** the top-level\n  `Makefile` **or** `client/CMakeLists.txt`. Keep both build definitions in sync.\n- `client/experimental_lib/` — experimental shared-lib build of the client,\n  has its own `CMakeLists.txt`. Any change to the client `client/CMakeLists.txt` almost always implies a change in `client/experimental_lib/CMakeLists.txt`.\n- `common_arm/`, `common/` — shared code between firmware and/or client.\n- `tools/` — standalone tool suites (`hitag2crack`, `mfc/*`, `fpga_compress`,\n  `ePassport`, etc.), each with its own `Makefile` and its own `check` target.\n\n## Before opening a PR: build matrix\n\nDo not treat \"it compiles for me\" as done. For any non-trivial change, verify\nacross the axes below (skip only the ones genuinely unaffected by your diff,\nand say explicitly in the PR description which axes you *did* and *did not*\ntest):\n\n1. **Zero warnings.** `make clean && make all` must complete with no compiler\n   warnings on the default toolchain (gcc). Warnings are effectively treated\n   as errors in this project's normal dev flow.\n2. **Second compiler.** Also try building host client and host tools (if touched) with clang, e.g. `make clean && make client -j CC=clang CXX=clang++ LD=clang++`\n   and fix anything it flags that gcc didn't — clang's\n   diagnostics catch different classes of bugs (e.g. some format-string and\n   sign issues).\n3. **Both client build systems.** If you touched client code, dependencies,\n   or build flags, update and test:\n   - `client/Makefile` (default `make client`)\n   - `client/CMakeLists.txt`\n   - `client/experimental_lib/CMakeLists.txt`\n   A file added to one and not the others is an incomplete PR.\n4. **ARM firmware targets.** If you touched `armsrc/`, `bootrom/`,\n   `common_arm/`, or anything reachable from firmware, compile at least for **both**\n   main platform configs (`PLATFORM=` per `Makefile.platform`): PM3RDV4 and PM5.\n   Use also PLATFORM_EXTRAS if relevant to your changes.\n5. **Cross-OS for platform-sensitive code.** Anything touching serial/USB\n   comms, filesystem paths, threading, or conditional `#ifdef _WIN32` /\n   `__APPLE__` / `__linux__` code needs to at least be reasoned through, and\n   ideally exercised, on all three supported environments: native Linux,\n   Windows (ProxSpace or WSL, per the project's documented Windows build\n   path), and macOS. Say in the PR which of these you actually ran.\n6. **Offline tests.** Run `make check` (or the narrower `<target>/check`,\n   e.g. `client/check`, `armsrc/check`) and make sure it stays green. Add to\n   `tools/pm3_tests.sh` coverage if you're adding a new command/module that\n   can be exercised offline.\n\n### Never `rm -rf` an `obj/` directory\n\nThe ARM-side build has no `mkdir` for its object directories — only the host\nbuild creates its own. `armsrc/obj/`, `armsrc/obj/Standalone/` and\n`bootrom/obj/` exist because each is held open in git by a tracked `.dummy`\nfile, and `make clean` deliberately deletes only the files *inside* them.\nDelete such a directory and nothing recreates it. Every subsequent build dies\nwith messages that give no hint a tracked file went missing:\n\n```\nError. Cannot open output file obj/fpga_all.bit.z\nFatal error: can't create obj/start.o: No such file or directory\n```\n\n`git checkout -- armsrc/obj/.dummy armsrc/obj/Standalone/.dummy bootrom/obj/.dummy`\nputs it back. `git status` showing a deleted `.dummy` is the tell.\n\nIf you script a build matrix, switch `PLATFORM=` / `STANDALONE=` and let make\ndecide what to rebuild — changing those changes the defines, which is enough to\nforce the recompile you want.\n\n## Code style\n\n- Respect the style used in this project: trailing\n  whitespace/EOL cleanup, Equivalent of `astyle` on `*.c`/`*.h` with \n  `--style=google --indent=spaces=4 --indent-switches --keep-one-line-blocks\n  --max-continuation-indent=60 --pad-oper --unpad-paren --pad-header\n  --align-pointer=name` and on `*.cpp`/`*.hpp` (same, minus `--pad-oper`).\n  Don't hand-format C/C++ differently from what `astyle` produces.\n- Don't reformat existing code outside of your changes, only format your own code.\n- If your change adds/changes a client command, run `make commands` to\n  regenerate `doc/commands.md` and `doc/commands.json` — don't hand-edit\n  those generated files.\n- **Keep comments short and direct.** This codebase comments in brief fragments,\n  usually one line. Match the surrounding file. No walls of text. A comment earns\n  its place by saying something the code cannot e.g. a return contract, where a\n  magic number came from, or why something is deliberately absent. Do not restate\n  the code or place commit message content, reasoning, or justification into the\n  source. Anything longer than 3-4 lines usually belongs in the PR instead.\n- **Preserve existing comments** in code you touch or move. Don't drop,\n  \"clean up\", or silently reword neighboring comments as a side effect of an\n  unrelated change.\n- Keep the GPLv3 file header banner (see any existing `.c`/`.h`/`Makefile`)\n  on new files; copy it verbatim from a neighboring file of the same type.\n\n## PR description format\n\nStructure the PR description in these sections:\n\n- **Problem** — what's actually wrong today, with concrete symptoms/examples,\n  not just \"code is messy.\"\n- **Change** — what you did, file by file if it helps a reviewer, and *why*\n  this approach (e.g. why runtime computation instead of a regenerated table).\n- **Behaviour change** — call out explicitly, as its own section, anything a\n  user or downstream code could observe differently after your change, even\n  if the new behavior is strictly more correct. Don't let this hide inside\n  the diff.\n- **Testing** — be specific and be honest:\n  - List the exact build variants exercised, e.g. \"readline (`make`),\n    linenoise (`SKIPREADLINE=1`), CMake client, `experimental_lib` (LIBPM3),\n    `PLATFORM=PM5` and default RDV4.\"\n  - Explicitly state what you did **not** test (e.g. \"Not tested here:\n    Windows/ProxSpace and macOS\") rather than implying full coverage. Where\n    possible, give a one-line reason the untested paths are low-risk (e.g.\n    \"only uses `scandir`/`alphasort`, already used portably elsewhere in\n    `fileutils.c`\").\n  - Net diff size and notable deletions are worth mentioning — removing a\n    stale generated table or dead code is a feature of the PR, not a\n    side note.\n\n## PR checklist (put this in the PR description)\n\n- [ ] Proper style of own code, no unrelated reformatting included\n- [ ] Builds warning-free with gcc; also tried with clang\n- [ ] `client/Makefile`, `client/CMakeLists.txt`, and\n      `client/experimental_lib/CMakeLists.txt` all updated if client sources\n      changed\n- [ ] ARM firmware builds clean for RDV4 and PM5 platform configs (if\n      `armsrc`/`bootrom`/`common_arm` touched)\n- [ ] Platform-sensitive code reasoned about / tested on Linux, Windows\n      (ProxSpace/WSL), and macOS (if applicable) — state which were tested\n- [ ] Existing comments in touched files preserved\n- [ ] New comments short and direct, no restated code or PR prose\n- [ ] `doc/commands.md` / `doc/commands.json` regenerated if commands changed\n\n## Commit attribution\n\nIf an AI agent authored or materially contributed to a commit, say so with a\ntrailer, the same way you'd credit a human co-author, e.g.:\n\n```\nCo-Authored-By: <agent/model name> <noreply@anthropic.com>\n```\n\nDon't omit this to make a PR look purely human-written.\n\n## What not to do\n\n- Don't add `-Werror`-suppressing flags or `#pragma` warning silences to make\n  a warning disappear — fix the underlying issue.\n- Don't introduce a dependency in one client build file without mirroring it\n  in the other two.\n- Don't submit ARM-side changes only test-built for one platform target.\n- Don't `rm -rf` any `obj/` directory to force a rebuild — it deletes tracked\n  `.dummy` files and breaks the build until they are restored. Use `make clean`.\n","tools/hitag2crack/README.md":"HiTag2 Cracking Suite\n---------------------\n\nAuthors:\n\n* Attacks 1, 2, 3, 4 : Kevin Sheldrake <kev@headhacking.com>\n* Attacks 5, 5gpu : anonymous, based on https://github.com/factoritbv/hitag2hell by FactorIT B.V.\n* Attack  5opencl : Gabriele Gristina <gabriele.gristina@gmail.com>, based on 5gpu\n\nIntroduction\n------------\n\nThese tools are implementations of the four attacks detailed in the papers,\nGone In 360 Seconds - Hijacking With HiTag 2 by Roel Verdult, Flavio Garcia\nand Josep Balasch, and Lock It And Still Lose It - on the (In)Security of\nAutomotive Remote Keyless Entry Systems by Flavio Garcia, David Oswald,\nTimo Kasper and Pierre Pavlides.  The first three attacks come from the first\npaper and the fourth attack comes from the second paper.\n\n\n_note_\nThere are no Proxmark3 client implemented commands for these attacks. Only separate executables to be compiled and run on your own system.\nNo guarantees of working binaries on all systems.  Some work on linux only. \nThere is no easy way to extract the needed data from a live system and use with these tools.\nYou can use the `RFIdler` device but the Proxmark3 client needs some more love.  Feel free to contribute.\n\nAttack 1\n--------\n\nAttack 1 is a nonce replay and length extension attack.  This is an attack on\na single HiTag2 RFID tag, given a single encrypted nonce and challenge\nresponse value pair (nR, aR) for the tag's UID.  The attack runs entirely on\nthe Proxmark3 with it acting like a RWD that replays the same encrypted nonce\nand challenge response pair for every interaction; this fixes the key stream\nthat the tag's PRNG outputs to the same stream for every interaction.\n\nBy brute forcing a subset of the encrypted command space, the Proxmark3 finds a\nsingle valid encrypted command - invalid commands return a known unencrypted\nerror response so finding a valid one is simply a case of trying different\nvalues until a response other than the error response is received.\n\nIt then bit flips the valid encrypted command to find the other 15 valid\nencrypted commands.  By knowing the contents of page 0 - it's the UID that\nis presented in clear at the start of each interaction - it tries each\nencrypted response in turn, assuming each to be the encrypted version of\n'read page 0 non-inverted' and each response to be the encrypted version of\npage 0.\n\nFor each attempted command, it calculates the key stream that would have\ncorrectly generated the encrypted command and response:\ncommand ++ response XOR key stream = encrypted command ++ encrypted response\ntherefore:\nkey stream = command ++ response XOR encrypted command ++ encrypted response\n\nIt then tests the potentially recovered key stream by creating an encrypted\ncommand that consumes as much of it as possible, re-initialising with the same\nencrypted nonce and challenge response pair (to set the key stream to the\nsame stream as that which produced the encrypted command response it is\ntesting), and then sending this extended encrypted command.  If the response\nis not the error response, then the key stream is valid and the response is\nthe encryption of the page 0 contents (the UID).\n\nWhen one of the valid encrypted commands satisfies this situation, the\nrecovered key stream must be the output of the PRNG for the given encrypted\nnonce and challenge response pair.\n\nThe Proxmark3 then uses this key stream to encrypt commands and decrypt the\nresponses, and therefore requests the contents of all 8 pages.  Pages 1 and 2\ncontain the encryption key.\n\nAttack 2\n--------\n\nAttack 2 is a time/space trade off to recover the key for situations where the\ntag has been configured to prevent reading of pages 1 and 2.  This attack uses\na pre-computed table of 2^37 PRNG states and resultant PRNG output, sorted on\nthe PRNG output.  The Proxmark3 is used to recover 2048 bits of key stream using\na modification of attack 1 and this is used to search the table for matching\nPRNG output.  When the output is found, it is tested for validity (by testing\nprevious or following PRNG output) and then the PRNG state is rolled back to\nthe initialisation state, from which the unencrypted nonce and key can be\nrecovered.\n\nAttack 3\n--------\n\nAttack 3 is a cryptanalytic attack that focuses on the RWD and a bias in the\nPRNG output.  By capturing 136 encrypted nonce and challenge response pairs,\ncandidates for the first 34 bits of the key can be identified, and for each\nthe remaining 14 bits can be brute forced.\n\nAttack 4\n--------\n\nAttack 4 is a fast correlative attack on the key based on a number of captured\nencrypted nonce and challenge response pairs (up to 32, but 16 usually\nsufficient).  It starts by guessing the first 16 bits of the key and scores\nall these guesses against how likely they are to be the correct key, given the\nencrypted nonces and the keystream they should produce.  Each guess is then\nexpanded by 1 bit and the process iterates, with only the best guesses taken\nforward to the next iteration.\n\nAttack 5\n--------\n\nAttack 5 is heavily based on the HiTag2 Hell CPU implementation from https://github.com/factoritbv/hitag2hell by FactorIT B.V.,\nwith the following changes:\n\n* Main takes a UID and 2 {nR},{aR} pairs as arguments and searches for states producing the first aR sample, reconstructs the corresponding key candidates and tests them against the second nR,aR pair;\n* Reuses the Hitag helping functions of the other attacks.\n\nAttack 5gpu\n-----------\n\nAttack 5gpu is identical to attack 5, simply the code has been ported to OpenCL\nto run on GPUs and is therefore much faster than attack 5.\n\nAttack 5opencl\n--------------\n\nAttack 5opencl is an optimized OpenCL version based on 5gpu.\nIt runs on multi GPUs/CPUs and is faster than 5gpu.\n\nUsage details: Attack 1\n-----------------------\n\nAttack 1 requires a valid tag and a valid encrypted nonce and challenge\nresponse pair.  The attacker needs to obtain a valid tag and then use this to\nobtain a valid encrypted nonce and challenge response pair.  This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.   \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** example\n\n\nUsage details: Attack 2\n-----------------------\n\nAttack 2 requires the same resources as attack 1, plus a pre-computed table.\nThe table can be generated on a disk with >1.5TB of storage, although it takes\nsome time (allow a couple of days, privilege SSD). This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.  \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\n./ht2crack2gentest 1\n./runalltests.sh\n```\n\nUsage details: Attack 3\n-----------------------\n\nAttack 3 requires only interaction with the RWD and does not require a valid\ntag, although it does require a HiTag2 tag that the RWD will initially respond\nto; e.g. you could potentially use any HiTag2 tag as long as the RWD starts\nthe crypto handshake with it.  It requires >=136 encrypted nonce and challenge\nresponse pairs for the same tag UID.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** will be ht2 sim or sniff with actual tag ?\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py 000102030405 AABBCCDD 32 > hitag2_AABBCCDD_nrar_32emul.txt\n./ht2crack3test hitag2_AABBCCDD_nrar_32emul.txt 000102030405 AABBCCDD\n./ht2crack3 AABBCCDD hitag2_AABBCCDD_nrar_32emul.txt |grep -E -v '(trying|partial)'\nrm hitag2_AABBCCDD_nrar_32emul.txt\n```\n\nUsage details: Attack 4\n-----------------------\n\nAttack 4 requires the same information as attack 3, but only 16-32 encrypted\nnonce and challenge response pairs are required.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py AABBCCDDEEFF 12345678 32 > hitag2_12345678_nrar_32emul.txt\n./ht2crack4 -u 12345678 -n hitag2_12345678_nrar_32emul.txt -N 16 -t 500000 2>&1\nrm hitag2_12345678_nrar_32emul.txt\n```\n\nUsage details: Attack 5\n-----------------------\n\nAttack 5 requires two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5 12345678 71DA20AA 7EFDF3FA 2A4265F9 59653B07\n```\n\nUsage details: Attack 5gpu/5opencl\n----------------------------------\n\nAttacks 5gpu and 5opencl require two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5opencl 12345678 B438220C 944FFD74 942C59E3 3D450B34\n```\n\n5opencl supports a number of additional parameters, see [crack5opencl/README.md](/tools/hitag2crack/crack5opencl/README.md) for details.\n\nUsage details: Next steps\n-------------------------\n\nOnce the key has been recovered using one of these attacks, the Proxmark3 can\nbe configured to operate as a RWD and will capture tags using that key.\n\n**TODO** example\n\nTags can be copied with standard Proxmark3 commands.\n\n**TODO** example\n","tools/deprecated-hid-flasher/flasher/README.md":"Compilation notes\n=================\n\nBesides the global Proxmark3 requirements, this flasher compatible with very old firmwares requires the libusb 0.1 to work.\nSo you'll need to install the libusb 0.1 package first.\n\n* OSX: libusb-compat\n* Debian-alike: libusb-0.1-4 libusb-dev\n* Arch: libusb\n* Fedora: libusb-devel\n","tools/kgh/README.md":"# legic_kgh_tool\n\n## Running\n\n`legic_kgh_tool` reads KGH LEGIC card information, badge numbers, and stamps,\nand writes the supported KGH card layout.\n\nExamples:\n\n```bash\n./legic_kgh_tool COM13 read_badge_number\n./legic_kgh_tool COM13 read_info\n./legic_kgh_tool COM13 read_stamp\n./legic_kgh_tool COM13 read_stamp -o stamp.bin\n./legic_kgh_tool COM13 write_card 600001 --stamp-file stamp.bin\n```\n\nCommands:\n\n- `read_badge_number` prints the badge number only.\n- `read_info` prints one-line JSON.\n- `read_stamp` prints the stamp as 8 hex chars, or writes raw 4 bytes with `-o/--output-file`.\n- `write_card <badge> (--stamp-file <path> | --stamp-hex <8hex>)` writes the supported KGH layout.\n\nNotes:\n\n- Windows ProxSpace examples use `COM13`.\n- The stamp is 4 bytes and specific to your site.\n  It can be specified as a `.bin` file or as `--stamp-hex` (for example, `003EF417`).\n- You can retrieve the stamp from a supported KGH card with `read_info` or `read_stamp`.\n- Linux examples usually use `/dev/ttyACM0` or similar.\n- `--verbose` can be useful for `read_badge_number` and `write_card`, if they fail for mysterious reasons.\n\n## Building in ProxSpace (for Windows)\n\nDo this in ProxSpace:\n\n```bash\ncd ~/proxmark3/tools/kgh\nrm -rf build-lite\ncmake -G \"MSYS Makefiles\" -S . -B build-lite \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-lite --target legic_kgh_tool -j\nobjdump -p build-lite/legic_kgh_tool.exe | grep -i \"DLL Name\"\n```\n\n## Building Linux\n\n```bash\ncd tools/kgh\nrm -rf build-linux\ncmake -S . -B build-linux \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-linux --target legic_kgh_tool -j\nldd build-linux/legic_kgh_tool\n```\n\n## Static Link Notes\n\n- `legic_kgh_tool` is linked against `pm3rrg_rdv4_static`.\n- On MinGW, CMake adds `-static -static-libgcc` for the target.\n- Linux builds are not the same as the ProxSpace single-EXE deployment.\n- If CMakeCache paths change between ProxSpace and a native shell, delete the build dir and reconfigure.\n","tools/hitag2crack/crack3/README.md":"ht2crack3\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 136 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack3 UID NRARFILE\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\n\n\nTests\n-----\n\nIf you happen to know the key and want to check that all your nR aR values\nare valid (for high-powered demonstrations only, really) then you can use\nthe ht2crack3test program to check them.  It's otherwise massively pointless and a\ncomplete waste of space.\n\n```\n./ht2crack3test NRARFILE KEY UID\n```\n","tools/hitag2crack/crack5/README.md":"ht2crack5\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5 <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n","tools/hitag2crack/crack4/README.md":"ht2crack4\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 16 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack4 -u UID -n NRARFILE [-N nonces to use] [-t table size]\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\nThe number of nonces to use allows you to use less than 32 nonces to increase\nspeed.\nThe table size can be tweaked for speed.  Start with 500000 and double it each\ntime it fails to find the key.\n\n\n","tools/hitag2crack/crack5gpu_disabled/README.md":"ht2crack5gpu\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5gpu <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n","tools/mfc/card_reader/mf_nonce_brute_examples.md":"mf_nonce_brute\n==============\n\nNested autenticated sector key recovery tool\n-----------------------------------------------\n\nCompatible tags:\n* Mifare Classic 1k (4k)\n* Mifare Plus in SL1 mode\n\nTo recover keys to nested autenticated sectors you need a reader-card communication log. To get it use \nhardware tools that able to sniff communication (for example Proxmark3 or HydraNFC).\n\nThis enhanced version:  \nFirst 2 bytes should be bruteforced in phase 2 with mf_key_brute tool that interacts with a card.\n\nSample trace:\n```\n    93 70 fd ac f6 d8 7f 21 4f                            // select card with UID fdacf6d8\nTAG 08 b6 dd                                              // sak\n    60 04 d1 3d                                           // wanna auth block 0x04 with A key\nTAG ed 12 9c 74                                           // 1st auth clear text nt\n    55 53 9f cc 41 8d e8 f3                               // {nr}, {ar}  (nr^ks1, ar^ks2 )\nTAG 05 49 e1 65                                           // {at} ( at^ks3 )\n    03 24 26 56                                           // wanna read block 0x04\nTAG ac 69 ef 58 45 e1 c2 1d a9 47 a5 94 54 ef 5d c7 1e a9 // block 0x04 content\n    d4 3e a8 aa \nTAG 8e 8e e3 e6 e9 e2 5f dd f6 08 ce fb 02 6a db 75 94 2f \n    79 77 68 3c \nTAG e0 00 00 80 80 08 cc 80 08 9c 82 e0 68 64 60 30 91 60  // 18 bytes = 16 byte content + 2 bytes crc\n    ea 88 c3 c2                                            // 4 byte read cmd\nTAG a3 76 dc df c1 42 e0 ee c6 75 a4 ca eb 0c da eb 46 a0  // 18 bytes = 16 byte content + 2 bytes crc ks8 + crc\n    2d 27 ab 6f                                            // wanna auth to 0x04 block with key B\n\n-------Until this line we can recover key or decrypt communication with no troubles (see mfkey64 tool)--------------------------------\n\nTAG 52 6e af 8b                                            // nested auth encrypted tag nonce that we don't know\n    8e 21 3a 29 a4 80 7e 02                                // {nr} = nr^ks1, {ar} = ar^ks2\nTAG b9 43 74 8d                                            // {at} = at^ks3\n    e2 25 f8 32                                            // probably next command (actually is read block cmd, but we don't know it yet)\nTAG 1f 26 82 8d 12 21 dd 42 c2 84 3e d0 26 7f 6b 2a 81 a9  // probably data\n    ba 85 1d 36                                            // probably read cmd\nTAG 62 a8 78 69 ee 36 22 16 1c ff 4b 4e 69 cb 27 c2 e8 7e  // probably data\n    a7 b1 c8 da                                            // probably read cmd\nTAG b2 fc 6c 65 60 ec 35 83 87 56 e3 7e 3c bf 38 b8 73 21  // probably data\n    99 92 13 55                                            // probably read cmd\nTAG 93 5b 65 a3 1d 8c 75 b8 3a 63 e2 31 f0 d0 a9 24 9a f6  // probably data\n```\n\n\nPhase 1\n-------\n\nSyntax:  \n`mf_nonce_brute <uid> <{nt}> <nt_par_err> <{nr}> <{ar}> <ar_par_err> <{at}> <at_par_err> [<{next_command}>]`\n\nExample: if `{nt}` in trace is `8c!  42 e6! 4e!`, then `{nt}` is `8c42e64e` and `nt_par_err` is `1011`\n\nExample with parity (from this trace http://www.proxmark.org/forum/viewtopic.php?pid=550#p550) :\n\n```\n + 561882:  1 :     26\n +     64:  2 : TAG 04  00\n +  10217:  2 :     93  20\n +     64:  5 : TAG 9c  59  9b  32  6c                        UID\n +  12313:  9 :     93  70  9c  59  9b  32  6c  6b  30\n +     64:  3 : TAG 08  b6  dd\n + 923318:  4 :     60  00  f5  7b                            AUTH Block 0\n +    112:  4 : TAG 82  a4  16  6c                            Nonce Tag (nt)\n +   6985:  8 :     a1  e4! 58  ce! 6e  ea! 41  e0!           {nr}, {ar}\n +     64:  4 : TAG 5c! ad  f4  39!                           {at}\n + 811513:  4 :     8e  0e! 5d! b9                            AUTH Block 0 (nested)\n +    112:  4 : TAG 5a! 92  0d! 85!                           Nonce Tag ({nt})\n +   6946:  8 :     98! d7  6b! 77  d6  c6  e8  70            {nr}, {ar}\n +     64:  4 : TAG ca  7e! 0b! 63!                           {at}\n + 670868:  4 :     3e! 70  9c! 8a\n +    112:  4 : TAG 36! 41  24! 79\n +   9505:  8 :     1b! 8c  3a! 48! 83  5a  4a! 27\n +     64:  4 : TAG 40! 6a! 99! 4b\n + 905612:  4 :     c9  7c  64! 13!                           !crc\n +    112:  4 : TAG b5! ab! 1d! 2b\n +   6936:  8 :     7e! d2  5c! ca! 4b! 50! 88! c4            !crc\n +     64:  4 : TAG bf  dd  01  be!\n + 987853:  4 :     56  98  49  d6!                           !crc\n```\n=> Using the plaintext tagnonce `nt`=`82a4166c`\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001 8e0e5db9  \n                 |        |        |     |        |        |    |        |    |\n                 +UID     +nt      |     +{nr}    +{ar}    |    +{at}    |    +{next cmd}\n                                   + nt is clear           +ar_par_err   +at_par_err\n```\n\nWithout a next command, it still finds a possible key candidate.\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85`, it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85` and the encrypted cmd `3e709c8a` to validate , it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\n```\nFull output:\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\nMifare classic nested auth key recovery. Phase 1.\n-------------------------------------------------\nuid:            9c599b32\nnt encrypted:   5a920d85\nnt parity err:  1011\nnr encrypted:   98d76b77\nar encrypted:   d6c6e870\nar parity err:  0000\nat encrypted:   ca7e0b63\nat parity err:  0111\nnext cmd enc:   3e709c8a\n\n\nStarting 4 threads to bruteforce encrypted tag nonce last bytes\nCMD enc(3e709c8a)\n    dec(6000f57b)       <-- Valid cmd\n\nValid Key found: [ffffffffffff]\n\nTime in mf_nonce_brute (Phase 1): 1763 ticks 2.0 seconds\n```\n\n[2024-07-11]\nThere is an odd case where we find multiple valid MIFARE Classic protocol commands with a valid ISO14443-A CRC when decrypting four bytes and are bruteforcing the last upper 16 bit of keyspace in phase 3. \n\nThe command has been updated to give a more informative text in order to help the user understanding and what to do next.\n\n```\n./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n```\n\n\nWhen running you get the following full output\n\n```\n./mf_nonce_brute$ ./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n\nMifare classic nested auth key recovery\n\n----------- information ------------------------\nuid.................. fcf77b54\nnt encrypted......... 1b456bdd\nnt parity err........ 1110\nnr encrypted......... 00f215b6\nar encrypted......... f9eb95e9\nar parity err........ 0011\nat encrypted......... bf55d0b1\nat parity err........ 0000\nnext encrypted cmd... AAD4126B\n\nBruteforce using 8 threads\n\n----------- Phase 1 pre-processing ------------------------\nTesting default keys using NESTED authentication...\n\n----------- Phase 2 examine -------------------------------\nLooking for the last bytes of the encrypted tagnonce\n\nTarget old MFC...\nCMD enc( aad4126b )\n    dec( 302424cf )    <-- valid cmd\n\nKey candidate [ ....37afcc2b ]\nKey candidate [ a70d37afcc2b ]\n\nexecution time 0.47 sec\n\n----------- Phase 3 validating ----------------------------\nuid.................. fcf77b54\npartial key.......... 37afcc2b\npossible key......... a70d37afcc2b\nnt enc............... 1b456bdd\nnr enc............... 00f215b6\nnext encrypted cmd... AAD4126B\n\nLooking for the upper 16 bits of the key\n\nenc:  AAD4126B\ndec:  610BFEDC\n\nValid Key found [ 7c2337afcc2b ]\n\n\nenc:  AAD4126B\ndec:  302424CF\n\nValid Key found [ a70d37afcc2b ] - matches candidate\n\n\nOdd case but we found 2 possible keys\nYou need to test all of them manually, start with the one matching the candidate\n\n```\n\n","tools/hitag2crack/crack5opencl/README.md":"ht2crack5opencl\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5opencl <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n\nUsage:\n\n```\n$ ./ht2crack5opencl\n./ht2crack5opencl [options] {UID} {nR1} {aR1} {nR2} {aR2}\n\nOptions:\n-p     : select OpenCL Platform(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-d     : select OpenCL Device(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-D     : select OpenCL Device Type. 0: GPU, 1: CPU, 2: all. [Default: GPU]\n-S     : select the thread scheduler type. 0: sequential, 1: asynchronous. [Default 1]\n-P     : select the Profile, from 0 to 10. [Default: auto-tuning]\n-F     : force verify key with OpenCL instead of CPU. [Default: disabled]\n-Q     : select queue engine. 0: forward, 1: reverse, 2: random. [Default: 0]\n-s     : show the list of OpenCL platforms/devices, then exit\n-V     : enable debug messages\n-v     : show the version\n-h     : show this help\n```\n\nExample,\n\n```\nsimple\n\n./ht2crack5opencl 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n\nselect devices 1, 2 and 3 using platform 1 and 2, with random queue engine:\n\n./ht2crack5opencl -D 2 -Q 2 -p 1,2 -d 1,2,3 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n```\n\n\nYou can find the correct OpenCL Platform ID (-p) and Device ID (-d) with:\n\n```\n./ht2crack5opencl -s\n```\n","tools/hitag2crack/crack2/README.md":"ht2crack2 suite\n\n\n\nBuild\n-----\n\nEdit ht2crack2buildtable.c and set the DATAMAX, NUM_BUILD_THREADS and NUM_SORT_THREADS values.\nThese are important if you want it to run quickly.  Ideally set DATAMAX to the largest value\nthat you can get away with and set NUM_BUILD_THREADS and NUM_SORT_THREADS to the number of\nvirtual cores you have available, which MUST be a power of 2.  NUM_BUILD_THREADS MUST be >=\nNUM_SORT_THREADS.\n\nCalculate DATAMAX = free RAM available / 65536, and then round down to a power of 10.\n\nThe Makefile is configured for linux.  To compile on Mac, edit it and swap the LIBS= lines.\n\n```\nmake clean\nmake\n```\n\nRun ht2crack2buildtable\n-----------------------\n\nMake sure you are in a directory on a disk with at least 1.5TB of space.\n\n```\n./ht2crack2buildtable\n```\n\nWait a very long time.  Maybe a few days.\n\nThis will create a directory tree called table/ while it is working that will contain\nfiles that will slowly build up in size to approx 20MB each.  Once it has finished making\nthese unsorted files, it will sort them into the directory tree sorted/ and remove the\noriginal files.  It will then exit and you'll have your shiny table.\n\n\nTest with ht2crack2gentests\n---------------------------\n\n```\n./ht2crack2gentests NUMBER_OF_TESTS\n```\n\nto generate NUMBER_OF_TESTS test files.  These will all be named\nkeystream.key-KEYVALUE.uid-UIDVALUE.nR-NRVALUE\n\nTest a single test with\n\n```\n./runtest.sh KEYSTREAMFILE\n```\nor manually with\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n\nor run all tests with\n```\n./runalltests.sh\n```\n\nFeel free to edit the shell scripts to find your tools.  You might want to create a\nsymbolic link to your sorted/ directory called 'sorted' to help ht2crack2seach find the\ntable.\n\nIf the tests work, then the table is sound.\n\n\nSearch for key in real keystream\n--------------------------------\n\nRecover 2048 bits of keystream from the target RFID tag with the RFIDler.  You will have had\nto supply an NR value and you should know the tag's UID (you can get this using the RFIDler).\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n","tools/mfc/card_reader/mfkey_examples.md":"# Card_reader Skill\n\nPath: `tools/mfc/card_reader/mfkey_examples.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/mfc/card_reader/mfkey_examples.md)","tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md":"# OpenCL-Headers Skill\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md)","tools/hitag2crack/common/OpenCL-Headers/README.md":"# OpenCL-Headers Documentation\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/README.md)"},"files":{"tools/ePassport/README.md":"# ePassport\n\nAn ePassport (eMRTD) viewer: reads a passport chip through the Proxmark3 and\nrenders it as a passport data page.\n\nEverything runs **offline**. No telemetry, no cloud OCR, no network calls of\nany kind — every font and asset is bundled.\n\n```\n./ePassport.py                                   # normal use\n./ePassport.py --dump DIR                       # open a saved dump, no hardware\n./ePassport.py --dry-run pm3.log --dump DIR     # replay a session you recorded\n./ePassport.py --help\n```\n\n`ePassport.py` is a plain launcher script — run it directly (it has a shebang) or with `python3`, from anywhere, by path or\nfrom a symlink; there is nothing to install and no `PYTHONPATH` to set. If a\ndependency is missing it says which one, which interpreter it used, and the\nexact command to fix it.\n\nIt needs an interpreter that has the requirements. With a virtualenv, either\nactivate it first or point at it directly:\n\n```bash\n/path/to/venv/bin/python ./ePassport.py\n```\n\n---\n\n## Install\n\n```bash\npython3 -m pip install -r requirements.txt\n```\n\nKivy is required. Everything else is optional and the app degrades with a\nmessage telling you what to install:\n\n| Missing | What stops working |\n|---|---|\n| `opencv-python-headless` | the Scan screen (camera) |\n| `pytesseract` + the `tesseract-ocr` binary | MRZ OCR — manual entry still works |\n| `Pillow` / `glymur` | portrait decoding (DG2 is usually JPEG2000) |\n| `asn1crypto` / `cryptography` | EF_SOD inspection and the DG hash table |\n\nFor the best OCR accuracy install the OCR-B or `mrz` traineddata; the app picks\nit up automatically and falls back to `eng` with a character whitelist.\n\n`sudo apt install xclip` enables Kivy's cut-buffer support. The app filters\nthe noisy `[CRITICAL] [Cutbuffer]` complaint either way; nothing depends on it.\n\n## Relationship to proxmark3\n\nThis app **does not modify the proxmark3 tree**. The only coupling is the `pm3`\nCLI, invoked in one-shot command mode:\n\n```\npm3 -c \"hf emrtd dump -n <DOCNUM> -d <YYMMDD> -e <YYMMDD> --dir <outdir>\"\npm3 -c \"hf emrtd info --dir <existing dump>\"     # offline mode\n```\n\nThe binary is located via `$PM3_BIN` → the configured path → `PATH` → `~/pm3/pm3`\n→ the `./pm3` wrapper of an enclosing proxmark3 source tree.\n\nThe country-name table in `emrtd/countries.py` is **generated** from the\nproxmark3 client's own ISO-3166 table (`fdxbCountryMapping` in\n`client/src/cmdlffdxb.c`). Regenerate it with:\n\n```bash\npython3 tools_gen_countries.py ../../client/src/cmdlffdxb.c\n```\n\n### Authentication\n\n| You have | Enter | What runs |\n|---|---|---|\n| The MRZ | document number + both dates, or line 2 | PACE with the MRZ, falling back to BAC |\n| The CAN | the number printed on the data page | `--can` (PACE only) |\n\nThe **CAN** is the short number printed on the data page — usually 6 digits.\nIt is a PACE password, so it is mutually exclusive with the MRZ, and BAC can\nnever use it. The Authentication dropdown forces `--pace` or `--bac` when you\nwant to test one path; leave it on Automatic otherwise.\n\nWrong CANs are counted by the chip and the password will eventually block, so\nthat failure is called out separately from a wrong MRZ.\n\n### Two things worth knowing about `hf emrtd`\n\n- **All three of `-n/-d/-e` must be supplied**, or the client silently drops to\n  no-BAC mode and fails on any protected passport. The app refuses a partial\n  triple rather than passing it on.\n- **The `pm3` wrapper blocks forever** waiting for a device when none is\n  attached. The app watches for that line and reports \"No Proxmark3 found\"\n  immediately instead of sitting on the timeout.\n\n## Using it\n\n1. **Scan** the MRZ with a camera, or **type** the three values. A full 44-char\n   MRZ line 2 takes precedence and is passed as `-m`, which avoids\n   field-splitting mistakes.\n2. **Read** — pm3 runs on a worker thread and streams into the LOG tab, with a\n   determinate progress bar and a Cancel that actually kills the process.\n3. The dump is parsed from the **binaries** (BER-TLV), never scraped from\n   `hf emrtd info` stdout, and rendered as a data page.\n\nTabs across the top: `DATA PAGE` · `PERSONAL` (DG11) · `ISSUER` (DG12) ·\n`SECURITY` (SOD/DG14/DG15) · `FILES` · `LOG`.\n\n### Output\n\nThe app is quiet by default. Kivy 2.3 takes its log level from\n`~/.kivy/config.ini`, which is shared with every other Kivy app on the machine,\nso rather than rewrite that the app drops Kivy's console handler and installs\nits own for warnings and above. pytesseract (which logs a full tesseract\ncommand line per frame), OpenCV and its V4L2 backend are quietened the same\nway. `-v` puts all of it back.\n\n### Resizing\n\nThe page is laid out **once** at a fixed resolution and then drawn scaled, so a\nresize costs a matrix multiply rather than a full re-flow. Re-flowing it on\nevery resize event re-rendered every label and regenerated the security print\nseveral times a frame, which made dragging a window edge crawl and the contents\njitter as text reflowed under the cursor.\n\nMeasured over twenty resize steps:\n\n| | Before | After |\n|---|---|---|\n| Page widget redraws per step | 21 | 0 |\n| Label re-renders per step | 65 | 11 (window chrome only) |\n| Time in text rendering | 182 ms | 10 ms |\n\nTwo supporting fixes: redraws are coalesced onto a `Clock` trigger so `pos` and\n`size` changing separately cannot cause three redraws in one frame, and MRZ\nglyphs are cached per (character, size) — an MRZ is ~90 characters drawn from\nan alphabet of 37, so it was building ninety textures to show at most\nthirty-seven distinct ones.\n\n### Why a document may not fill the window\n\nBoth formats are always scaled as large as they fit without distorting, so\nneither is ever \"shrunk\" — but a document and a window are different shapes,\nand only one of the two dimensions can fill. Whichever document is closer to\nthe window's shape uses more of it:\n\n| Window content shape | Passport (1.42) | Card (1.59) |\n|---|---|---|\n| 1.61 (wide) | 88% wide, 100% tall | 99% wide, 100% tall |\n| 1.42 (the default) | **100% wide, 100% tall** | 100% wide, 90% tall |\n| 2.59 (very wide) | 55% wide, 100% tall | 61% wide, 100% tall |\n\nThe default window is sized so its **content area comes out at the reference\ndocument's own 125:88**, so a passport fills it exactly on first run. Stretch\nthe window wide and both documents will letterbox at the sides; that is the\nshape mismatch, not the app giving up on the space.\n\n### Small windows\n\nThe minimum window is 760x520 and the app remembers the size you leave it at.\nEverything is built to survive that:\n\n- the passport page scales as a unit and keeps its aspect;\n- the tab strip shares its width rather than claiming fixed slots;\n- the FILES table uses proportional columns, so the state column does not fall\n  off the edge;\n- the hex viewer fits **16, 8 or 4 bytes per row** to whatever width the pane\n  has, because a hex dump must not wrap.\n\n### Speed\n\nAn MRZ scan settles in roughly a second. What that took:\n\n| Change | Effect |\n|---|---|\n| Cheap pre-gate before OCR (`looks_like_text`) | a badly framed strip costs ~0.3 ms instead of ~400 ms |\n| Skip frames already processed | no repeat OCR of an identical frame |\n| Pace the loop instead of adding to it | the interval no longer stacks on top of the work |\n| Cache the language lookup | it shelled out to tesseract every frame |\n| Stop escalating variants with no signal | 2 passes instead of 3 on hopeless frames |\n| Remember the last winning variant | dim lighting costs 1 pass, not 3 |\n\nMeasured on a live camera: mean OCR pass 381 ms → 163 ms, time to acceptance\n3.1 s → 1.3 s, with accuracy unchanged on the synthetic bench.\n\nThe gate runs *after* deskew — it measures horizontal bands of ink, and tilted\ntext smears those bands together.\n\nAn in-process binding (`tesserocr`) is ~3× faster per call than re-launching\nthe tesseract binary, and was tried. It is **not** used: the PyPI wheel bundles\nits own leptonica, and pairing that with a system `tessdata` directory hung\nindefinitely mid-recognition. A backend that can wedge the OCR thread is worse\nthan a slower one.\n\n### Cameras\n\nThe Scan screen enumerates capture devices by name from\n`/sys/class/video4linux` — without opening them, because opening a device is\ndisruptive if something else is using it.\n\n- **No camera**: the screen says so and offers **Rescan for devices**. Manual\n  entry is always available and works just as well.\n- **One or more**: a dropdown lists them by name (`0: IPEVO Ziggi-HD Plus`).\n  The choice is remembered.\n\nLinux commonly exposes several `/dev/videoN` nodes for one physical camera,\nonly one of which delivers frames — `isOpened()` returns true for the others.\nThe app therefore treats a successful *read* as the test, and falls back to a\nneighbouring index automatically. **Rescan** probes every device to label the\ndead ones `(no frames)`; it stops the preview first so the probe and the\ncapture thread do not fight over the device.\n\nOnly line 2 is needed for BAC, so the scan accepts a lone line 2 when its five\ncheck digits — composite included — all pass.\n\n### What a \"valid\" MRZ scan does and does not prove\n\nA scan is accepted only when every check digit validates **and** two\nconsecutive frames agree. That still does not prove the document number is\nright. The 7-3-1 checksum is taken modulo 10 and its weights are coprime with\n10, so swapping a character for one whose value differs by a multiple of 10\nleaves every check digit — composite included — unchanged. The blind pairs are\n`L`/`1`, `S`/`8`, `G`/`6`, `Z`/`5`, `I`/`8`, `D`/`3` … which are exactly the\nswaps OCR is most likely to make.\n\nThat is why a scan **fills the entry form and stops** rather than starting a\nread, and why the form flags the document number for a second look. If BAC\nthen fails, the document number is the first thing to check.\n\n(Confusions that are *not* blind, such as `O` read as `0` in a country code,\nare repaired automatically by position before validation.)\n\n### Drawing the page\n\nA TD1 is an ID-1 card (85.6 x 54 mm), not a small passport data page\n(125 x 88 mm), and its three-line MRZ takes about a quarter of its height\nagainst an eighth for a passport's two lines. The page is drawn at whichever\nshape the document really is.\n\n**Two scale modes**, because you cannot have both at once. OCR-B is a fixed\n2.54 mm pitch on every format, but a character is 2.97% of a card's width and\nonly 2.03% of a passport's — so a card's MRZ is inherently half again as large\nrelative to its own document:\n\n| Mode | What it gives you | What it costs |\n|---|---|---|\n| **Fit window** (default) | every document fills the window | a card's MRZ prints ~1.5x a passport's on screen |\n| **True size** | MRZ print identical across formats, as in the hand | a card is drawn two thirds the width, leaving margins |\n\nOpening a dump re-fits the page for whatever format it turns out to be, so the\nbutton is a preference you set once, not something to press after every load.\nThe toolbar button swaps them and the choice is remembered. It is labelled\nwith the **action**, like the chrome button beside it: reading \"Fit window\"\nmeans clicking will fit the window, so you are currently at true size. A\npassport looks identical either way; only formats smaller than the reference\npage differ.\n\nWithin the band, the MRZ block is sized to fit in **both** directions — the\nsmaller of the width- and height-derived sizes wins, and a block that does not\nfill the width is centred. Fitting the width alone pushed a card's MRZ out over\nthe fields above it; leaving a full line of air between rows then shrank it\nuntil it no longer reached the margins.\n\nThe **portrait** is sized from the page width and the real 35 x 45 photo shape,\ncapped against the space above the band — a fraction of page height alone made\nit swallow a short card. The frame keeps the photo aspect whichever constraint\nbinds, so an image never sits letterboxed in white bars.\n\nThe guilloche is generated procedurally (superimposed hypotrochoids at low\nalpha) — nothing is traced from a real document's security print. It is clipped\nto the printed frame **geometrically**, with a Liang-Barsky segment clip, not\nwith a stencil: this widget can sit inside another `StencilView`, and Kivy's\nnested stencils do not intersect, so an inner stencil silently stops clipping\nanything. That bug had the pattern spilling past the page edge onto the\nwindow background.\n\nText over the pattern measures about 15:1 contrast, well clear of the 4.5:1\nfloor.\n\n### Fields that may not be there\n\nDG11 and DG12 are optional and plenty of real passports omit them entirely —\nplace of birth, date of issue and issuing authority are printed on the page but\nnever written to the chip. Those fields say **\"not on chip\"** rather than\nshowing an empty value, so a missing data group is not mistaken for a parse\nfailure.\n\nThe **personal number** is recovered from the MRZ optional-data field when\nDG11 is absent — several states, Sweden among them, put the national identity\nnumber there. The field's caption says `PERSONAL No. (FROM MRZ)` when it came\nfrom that fallback.\n\n### What the SECURITY tab does and does not check\n\nIt hashes each dumped data group and compares against the hash table inside\nEF_SOD, marking every DG **match / MISMATCH / not checked**. It does **not**\nvalidate the signer certificate chain — that needs the issuing country's CSCA\ncertificate, which the app deliberately does not fetch.\n\n## Where your reads go\n\nEvery read writes to:\n\n```\n~/.local/share/ePassport/dumps/<UTC-timestamp>/\n```\n\ncreated `0700`. The app was previously called `pm3-passport`; if a directory\nof that name exists it is moved to the new one on first run, so earlier reads\nare carried across rather than orphaned. You do not need to remember that: **Dumps…** in the toolbar\nlists every read with its timestamp and contents. From there you can open one,\ndelete one with the bin button, open the folder in your file manager, or clear\nout the empty directories left behind by reads that failed. The path is also in\nthe status bar (click it) and in the log at the start of every read.\n\nEvery read also leaves `pm3.log` in its directory: the client output for that\nrun, which is the only record of why a read that dumped nothing gave up. It\nholds what the LOG pane showed and not the MRZ or CAN you typed, and it does\nnot count as a file when the app decides whether a read produced anything.\n\nDeleting always asks first, and says what it is about to destroy — a dump holds\na real portrait and a real MRZ.\n\n**Opening a dump from elsewhere** (a colleague's, or the generated samples):\n**Dumps… → Samples…** goes straight to `./samples`, and **Browse…** opens a\npicker with one-click jumps to **Recent**, **Dumps**, **Samples**, **Working\ndir** and **Home**, plus a path box you can type or paste into.\n\nThe picker reopens **beside the last dump you loaded**, so picking a second\ndump next to the first does not mean navigating there again. Shortcuts that do\nnot exist are not shown — `Samples` only appears once you have generated them —\nand duplicates collapse, so `Recent` and `Samples` do not both appear when they\nare the same folder.\n\n## Your data\n\n- Dumps are `0700` and there is a **Delete dump** button.\n- MRZ values and document numbers are never written outside that directory.\n- \"Remember\" on the entry screen defaults to **off** — those values are live\n  credential material.\n- The app is strictly read-only: it displays what the chip returns, and no\n  field is editable.\n\n## Development\n\n```bash\nmake test              # 297 tests, no hardware needed\nmake samples           # generate the fabricated dumps into ./samples\nmake clean             # drop __pycache__ and the test cache\nmake distclean         # the above, plus the generated samples\nmake format            # reformat with black\nmake help              # the rest\n```\n\nThe proxmark3 root `Makefile` recurses in here too, following the same pattern\nit uses for `hitag2crack`:\n\n```bash\nmake ePassport/clean     # from the repository root\nmake ePassport/test\nmake ePassport/help\n```\n\nePassport is deliberately **not** in the root `TARGETS`, so a plain `make` or\n`make clean` at the top level does not touch it — it builds nothing and is not\npart of the firmware or client build.\n\n`make` shells out to `python3`; if your dependencies live in a virtualenv,\npoint it at that interpreter:\n\n```bash\nmake test PYTHON=/path/to/venv/bin/python\n```\n\nThe same without `make`:\n\n```bash\npython3 -m pytest tests/ -q\npython3 tools_make_sample.py [DIR]              # generate the sample dumps\npython3 -m epassport.emrtd samples/td3_utopia   # headless: parse and print\npython3 -m black epassport tests tools_*.py\n```\n\n### Nothing derived from a document is checked in\n\nThis tree carries **no dumps, no logs and no images**. A dump holds a live\nportrait and MRZ, and a screenshot of one is just as identifying — so none of\nit belongs in version control, not even the fabricated kind, and `.gitignore`\nrefuses the file types outright.\n\nWhat you need instead is generated:\n\n```bash\npython3 tools_make_sample.py [DIR]      # fabricated dumps, default ./samples\n```\n\nThey are documents of the fictional ICAO specimen state \"Utopia\": no real\npersonal data, no real security print. `td3_utopia` carries a genuinely signed\nEF_SOD, `td3_utopia_tampered` is the same document with DG2 swapped after\nsigning so the SECURITY tab has a MISMATCH to show, and `td1_utopia_idcard` is\na TD1 card with no DG11/DG12 or SOD.\n\nThe tests never touch that directory: `tests/conftest.py` builds its own copy\ninto a temporary directory, and the recorded pm3 sessions used by the\n`--dry-run` tests are inline in `tests/test_pm3_client.py`.\n\nTo replay a real session, record it yourself:\n\n```bash\npm3 -c \"hf emrtd dump -n ... -d ... -e ...\" | tee pm3.log\n```\n\n### Layout\n\n```\nMakefile             run / test / format / clean\nePassport.py         the launcher; everything below is the implementation\nepassport/\n  app.py               app, screens, worker threads\n  __main__.py          shim so `python3 -m epassport` still works\n  config.py            paths, settings, 0700 data dir\n  pm3/client.py        subprocess, streaming, cancel, timeout\n  pm3/errors.py        typed failures + plain-English remedies\n  emrtd/tlv.py         BER-TLV reader\n  emrtd/mrz.py         TD1/TD2/TD3, check digits, date window\n  emrtd/dg.py          per-DG decoders -> PassportRecord\n  emrtd/sod.py         optional CMS/SOD inspection\n  emrtd/images.py      JPEG/JP2 carving out of CBEFF blobs\n  emrtd/model.py       PassportRecord: the single UI-facing object\n  ocr/                 camera thread, OCR pipeline, accept rule\n  ui/                  Kivy widgets and .kv files\n```\n\n**Threading contract:** the pm3 subprocess, file parsing, image decoding and\nOCR all run off the main thread; UI mutation happens only via\n`Clock.schedule_once`. The app never freezes while a dump runs.\n\n**Single source of truth:** every parser produces one `PassportRecord`, and the\nUI binds only to that — which is why \"open saved dump\" and \"read from card\" are\nthe same rendering path.\n","AGENTS.md":"# AGENTS.md\n\nInstructions for AI coding agents (and humans using one) proposing pull requests\nto this repository. This complements `README.md` and `Maintainers.md`; when in\ndoubt, those human-facing docs win.\n\n## Repo shape (quick map)\n\n- `bootrom/`, `armsrc/` — ARM firmware for the device (Proxmark3\n  hardware targets), buildable via **either** the top-level\n  `Makefile` **or** their respective `CMakeLists.txt`. Keep both build definitions in sync.\n- `client/` — host-side client, buildable via **either** the top-level\n  `Makefile` **or** `client/CMakeLists.txt`. Keep both build definitions in sync.\n- `client/experimental_lib/` — experimental shared-lib build of the client,\n  has its own `CMakeLists.txt`. Any change to the client `client/CMakeLists.txt` almost always implies a change in `client/experimental_lib/CMakeLists.txt`.\n- `common_arm/`, `common/` — shared code between firmware and/or client.\n- `tools/` — standalone tool suites (`hitag2crack`, `mfc/*`, `fpga_compress`,\n  `ePassport`, etc.), each with its own `Makefile` and its own `check` target.\n\n## Before opening a PR: build matrix\n\nDo not treat \"it compiles for me\" as done. For any non-trivial change, verify\nacross the axes below (skip only the ones genuinely unaffected by your diff,\nand say explicitly in the PR description which axes you *did* and *did not*\ntest):\n\n1. **Zero warnings.** `make clean && make all` must complete with no compiler\n   warnings on the default toolchain (gcc). Warnings are effectively treated\n   as errors in this project's normal dev flow.\n2. **Second compiler.** Also try building host client and host tools (if touched) with clang, e.g. `make clean && make client -j CC=clang CXX=clang++ LD=clang++`\n   and fix anything it flags that gcc didn't — clang's\n   diagnostics catch different classes of bugs (e.g. some format-string and\n   sign issues).\n3. **Both client build systems.** If you touched client code, dependencies,\n   or build flags, update and test:\n   - `client/Makefile` (default `make client`)\n   - `client/CMakeLists.txt`\n   - `client/experimental_lib/CMakeLists.txt`\n   A file added to one and not the others is an incomplete PR.\n4. **ARM firmware targets.** If you touched `armsrc/`, `bootrom/`,\n   `common_arm/`, or anything reachable from firmware, compile at least for **both**\n   main platform configs (`PLATFORM=` per `Makefile.platform`): PM3RDV4 and PM5.\n   Use also PLATFORM_EXTRAS if relevant to your changes.\n5. **Cross-OS for platform-sensitive code.** Anything touching serial/USB\n   comms, filesystem paths, threading, or conditional `#ifdef _WIN32` /\n   `__APPLE__` / `__linux__` code needs to at least be reasoned through, and\n   ideally exercised, on all three supported environments: native Linux,\n   Windows (ProxSpace or WSL, per the project's documented Windows build\n   path), and macOS. Say in the PR which of these you actually ran.\n6. **Offline tests.** Run `make check` (or the narrower `<target>/check`,\n   e.g. `client/check`, `armsrc/check`) and make sure it stays green. Add to\n   `tools/pm3_tests.sh` coverage if you're adding a new command/module that\n   can be exercised offline.\n\n### Never `rm -rf` an `obj/` directory\n\nThe ARM-side build has no `mkdir` for its object directories — only the host\nbuild creates its own. `armsrc/obj/`, `armsrc/obj/Standalone/` and\n`bootrom/obj/` exist because each is held open in git by a tracked `.dummy`\nfile, and `make clean` deliberately deletes only the files *inside* them.\nDelete such a directory and nothing recreates it. Every subsequent build dies\nwith messages that give no hint a tracked file went missing:\n\n```\nError. Cannot open output file obj/fpga_all.bit.z\nFatal error: can't create obj/start.o: No such file or directory\n```\n\n`git checkout -- armsrc/obj/.dummy armsrc/obj/Standalone/.dummy bootrom/obj/.dummy`\nputs it back. `git status` showing a deleted `.dummy` is the tell.\n\nIf you script a build matrix, switch `PLATFORM=` / `STANDALONE=` and let make\ndecide what to rebuild — changing those changes the defines, which is enough to\nforce the recompile you want.\n\n## Code style\n\n- Respect the style used in this project: trailing\n  whitespace/EOL cleanup, Equivalent of `astyle` on `*.c`/`*.h` with \n  `--style=google --indent=spaces=4 --indent-switches --keep-one-line-blocks\n  --max-continuation-indent=60 --pad-oper --unpad-paren --pad-header\n  --align-pointer=name` and on `*.cpp`/`*.hpp` (same, minus `--pad-oper`).\n  Don't hand-format C/C++ differently from what `astyle` produces.\n- Don't reformat existing code outside of your changes, only format your own code.\n- If your change adds/changes a client command, run `make commands` to\n  regenerate `doc/commands.md` and `doc/commands.json` — don't hand-edit\n  those generated files.\n- **Keep comments short and direct.** This codebase comments in brief fragments,\n  usually one line. Match the surrounding file. No walls of text. A comment earns\n  its place by saying something the code cannot e.g. a return contract, where a\n  magic number came from, or why something is deliberately absent. Do not restate\n  the code or place commit message content, reasoning, or justification into the\n  source. Anything longer than 3-4 lines usually belongs in the PR instead.\n- **Preserve existing comments** in code you touch or move. Don't drop,\n  \"clean up\", or silently reword neighboring comments as a side effect of an\n  unrelated change.\n- Keep the GPLv3 file header banner (see any existing `.c`/`.h`/`Makefile`)\n  on new files; copy it verbatim from a neighboring file of the same type.\n\n## PR description format\n\nStructure the PR description in these sections:\n\n- **Problem** — what's actually wrong today, with concrete symptoms/examples,\n  not just \"code is messy.\"\n- **Change** — what you did, file by file if it helps a reviewer, and *why*\n  this approach (e.g. why runtime computation instead of a regenerated table).\n- **Behaviour change** — call out explicitly, as its own section, anything a\n  user or downstream code could observe differently after your change, even\n  if the new behavior is strictly more correct. Don't let this hide inside\n  the diff.\n- **Testing** — be specific and be honest:\n  - List the exact build variants exercised, e.g. \"readline (`make`),\n    linenoise (`SKIPREADLINE=1`), CMake client, `experimental_lib` (LIBPM3),\n    `PLATFORM=PM5` and default RDV4.\"\n  - Explicitly state what you did **not** test (e.g. \"Not tested here:\n    Windows/ProxSpace and macOS\") rather than implying full coverage. Where\n    possible, give a one-line reason the untested paths are low-risk (e.g.\n    \"only uses `scandir`/`alphasort`, already used portably elsewhere in\n    `fileutils.c`\").\n  - Net diff size and notable deletions are worth mentioning — removing a\n    stale generated table or dead code is a feature of the PR, not a\n    side note.\n\n## PR checklist (put this in the PR description)\n\n- [ ] Proper style of own code, no unrelated reformatting included\n- [ ] Builds warning-free with gcc; also tried with clang\n- [ ] `client/Makefile`, `client/CMakeLists.txt`, and\n      `client/experimental_lib/CMakeLists.txt` all updated if client sources\n      changed\n- [ ] ARM firmware builds clean for RDV4 and PM5 platform configs (if\n      `armsrc`/`bootrom`/`common_arm` touched)\n- [ ] Platform-sensitive code reasoned about / tested on Linux, Windows\n      (ProxSpace/WSL), and macOS (if applicable) — state which were tested\n- [ ] Existing comments in touched files preserved\n- [ ] New comments short and direct, no restated code or PR prose\n- [ ] `doc/commands.md` / `doc/commands.json` regenerated if commands changed\n\n## Commit attribution\n\nIf an AI agent authored or materially contributed to a commit, say so with a\ntrailer, the same way you'd credit a human co-author, e.g.:\n\n```\nCo-Authored-By: <agent/model name> <noreply@anthropic.com>\n```\n\nDon't omit this to make a PR look purely human-written.\n\n## What not to do\n\n- Don't add `-Werror`-suppressing flags or `#pragma` warning silences to make\n  a warning disappear — fix the underlying issue.\n- Don't introduce a dependency in one client build file without mirroring it\n  in the other two.\n- Don't submit ARM-side changes only test-built for one platform target.\n- Don't `rm -rf` any `obj/` directory to force a rebuild — it deletes tracked\n  `.dummy` files and breaks the build until they are restored. Use `make clean`.\n","tools/hitag2crack/README.md":"HiTag2 Cracking Suite\n---------------------\n\nAuthors:\n\n* Attacks 1, 2, 3, 4 : Kevin Sheldrake <kev@headhacking.com>\n* Attacks 5, 5gpu : anonymous, based on https://github.com/factoritbv/hitag2hell by FactorIT B.V.\n* Attack  5opencl : Gabriele Gristina <gabriele.gristina@gmail.com>, based on 5gpu\n\nIntroduction\n------------\n\nThese tools are implementations of the four attacks detailed in the papers,\nGone In 360 Seconds - Hijacking With HiTag 2 by Roel Verdult, Flavio Garcia\nand Josep Balasch, and Lock It And Still Lose It - on the (In)Security of\nAutomotive Remote Keyless Entry Systems by Flavio Garcia, David Oswald,\nTimo Kasper and Pierre Pavlides.  The first three attacks come from the first\npaper and the fourth attack comes from the second paper.\n\n\n_note_\nThere are no Proxmark3 client implemented commands for these attacks. Only separate executables to be compiled and run on your own system.\nNo guarantees of working binaries on all systems.  Some work on linux only. \nThere is no easy way to extract the needed data from a live system and use with these tools.\nYou can use the `RFIdler` device but the Proxmark3 client needs some more love.  Feel free to contribute.\n\nAttack 1\n--------\n\nAttack 1 is a nonce replay and length extension attack.  This is an attack on\na single HiTag2 RFID tag, given a single encrypted nonce and challenge\nresponse value pair (nR, aR) for the tag's UID.  The attack runs entirely on\nthe Proxmark3 with it acting like a RWD that replays the same encrypted nonce\nand challenge response pair for every interaction; this fixes the key stream\nthat the tag's PRNG outputs to the same stream for every interaction.\n\nBy brute forcing a subset of the encrypted command space, the Proxmark3 finds a\nsingle valid encrypted command - invalid commands return a known unencrypted\nerror response so finding a valid one is simply a case of trying different\nvalues until a response other than the error response is received.\n\nIt then bit flips the valid encrypted command to find the other 15 valid\nencrypted commands.  By knowing the contents of page 0 - it's the UID that\nis presented in clear at the start of each interaction - it tries each\nencrypted response in turn, assuming each to be the encrypted version of\n'read page 0 non-inverted' and each response to be the encrypted version of\npage 0.\n\nFor each attempted command, it calculates the key stream that would have\ncorrectly generated the encrypted command and response:\ncommand ++ response XOR key stream = encrypted command ++ encrypted response\ntherefore:\nkey stream = command ++ response XOR encrypted command ++ encrypted response\n\nIt then tests the potentially recovered key stream by creating an encrypted\ncommand that consumes as much of it as possible, re-initialising with the same\nencrypted nonce and challenge response pair (to set the key stream to the\nsame stream as that which produced the encrypted command response it is\ntesting), and then sending this extended encrypted command.  If the response\nis not the error response, then the key stream is valid and the response is\nthe encryption of the page 0 contents (the UID).\n\nWhen one of the valid encrypted commands satisfies this situation, the\nrecovered key stream must be the output of the PRNG for the given encrypted\nnonce and challenge response pair.\n\nThe Proxmark3 then uses this key stream to encrypt commands and decrypt the\nresponses, and therefore requests the contents of all 8 pages.  Pages 1 and 2\ncontain the encryption key.\n\nAttack 2\n--------\n\nAttack 2 is a time/space trade off to recover the key for situations where the\ntag has been configured to prevent reading of pages 1 and 2.  This attack uses\na pre-computed table of 2^37 PRNG states and resultant PRNG output, sorted on\nthe PRNG output.  The Proxmark3 is used to recover 2048 bits of key stream using\na modification of attack 1 and this is used to search the table for matching\nPRNG output.  When the output is found, it is tested for validity (by testing\nprevious or following PRNG output) and then the PRNG state is rolled back to\nthe initialisation state, from which the unencrypted nonce and key can be\nrecovered.\n\nAttack 3\n--------\n\nAttack 3 is a cryptanalytic attack that focuses on the RWD and a bias in the\nPRNG output.  By capturing 136 encrypted nonce and challenge response pairs,\ncandidates for the first 34 bits of the key can be identified, and for each\nthe remaining 14 bits can be brute forced.\n\nAttack 4\n--------\n\nAttack 4 is a fast correlative attack on the key based on a number of captured\nencrypted nonce and challenge response pairs (up to 32, but 16 usually\nsufficient).  It starts by guessing the first 16 bits of the key and scores\nall these guesses against how likely they are to be the correct key, given the\nencrypted nonces and the keystream they should produce.  Each guess is then\nexpanded by 1 bit and the process iterates, with only the best guesses taken\nforward to the next iteration.\n\nAttack 5\n--------\n\nAttack 5 is heavily based on the HiTag2 Hell CPU implementation from https://github.com/factoritbv/hitag2hell by FactorIT B.V.,\nwith the following changes:\n\n* Main takes a UID and 2 {nR},{aR} pairs as arguments and searches for states producing the first aR sample, reconstructs the corresponding key candidates and tests them against the second nR,aR pair;\n* Reuses the Hitag helping functions of the other attacks.\n\nAttack 5gpu\n-----------\n\nAttack 5gpu is identical to attack 5, simply the code has been ported to OpenCL\nto run on GPUs and is therefore much faster than attack 5.\n\nAttack 5opencl\n--------------\n\nAttack 5opencl is an optimized OpenCL version based on 5gpu.\nIt runs on multi GPUs/CPUs and is faster than 5gpu.\n\nUsage details: Attack 1\n-----------------------\n\nAttack 1 requires a valid tag and a valid encrypted nonce and challenge\nresponse pair.  The attacker needs to obtain a valid tag and then use this to\nobtain a valid encrypted nonce and challenge response pair.  This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.   \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** example\n\n\nUsage details: Attack 2\n-----------------------\n\nAttack 2 requires the same resources as attack 1, plus a pre-computed table.\nThe table can be generated on a disk with >1.5TB of storage, although it takes\nsome time (allow a couple of days, privilege SSD). This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.  \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\n./ht2crack2gentest 1\n./runalltests.sh\n```\n\nUsage details: Attack 3\n-----------------------\n\nAttack 3 requires only interaction with the RWD and does not require a valid\ntag, although it does require a HiTag2 tag that the RWD will initially respond\nto; e.g. you could potentially use any HiTag2 tag as long as the RWD starts\nthe crypto handshake with it.  It requires >=136 encrypted nonce and challenge\nresponse pairs for the same tag UID.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** will be ht2 sim or sniff with actual tag ?\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py 000102030405 AABBCCDD 32 > hitag2_AABBCCDD_nrar_32emul.txt\n./ht2crack3test hitag2_AABBCCDD_nrar_32emul.txt 000102030405 AABBCCDD\n./ht2crack3 AABBCCDD hitag2_AABBCCDD_nrar_32emul.txt |grep -E -v '(trying|partial)'\nrm hitag2_AABBCCDD_nrar_32emul.txt\n```\n\nUsage details: Attack 4\n-----------------------\n\nAttack 4 requires the same information as attack 3, but only 16-32 encrypted\nnonce and challenge response pairs are required.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py AABBCCDDEEFF 12345678 32 > hitag2_12345678_nrar_32emul.txt\n./ht2crack4 -u 12345678 -n hitag2_12345678_nrar_32emul.txt -N 16 -t 500000 2>&1\nrm hitag2_12345678_nrar_32emul.txt\n```\n\nUsage details: Attack 5\n-----------------------\n\nAttack 5 requires two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5 12345678 71DA20AA 7EFDF3FA 2A4265F9 59653B07\n```\n\nUsage details: Attack 5gpu/5opencl\n----------------------------------\n\nAttacks 5gpu and 5opencl require two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5opencl 12345678 B438220C 944FFD74 942C59E3 3D450B34\n```\n\n5opencl supports a number of additional parameters, see [crack5opencl/README.md](/tools/hitag2crack/crack5opencl/README.md) for details.\n\nUsage details: Next steps\n-------------------------\n\nOnce the key has been recovered using one of these attacks, the Proxmark3 can\nbe configured to operate as a RWD and will capture tags using that key.\n\n**TODO** example\n\nTags can be copied with standard Proxmark3 commands.\n\n**TODO** example\n","tools/deprecated-hid-flasher/flasher/README.md":"Compilation notes\n=================\n\nBesides the global Proxmark3 requirements, this flasher compatible with very old firmwares requires the libusb 0.1 to work.\nSo you'll need to install the libusb 0.1 package first.\n\n* OSX: libusb-compat\n* Debian-alike: libusb-0.1-4 libusb-dev\n* Arch: libusb\n* Fedora: libusb-devel\n","tools/kgh/README.md":"# legic_kgh_tool\n\n## Running\n\n`legic_kgh_tool` reads KGH LEGIC card information, badge numbers, and stamps,\nand writes the supported KGH card layout.\n\nExamples:\n\n```bash\n./legic_kgh_tool COM13 read_badge_number\n./legic_kgh_tool COM13 read_info\n./legic_kgh_tool COM13 read_stamp\n./legic_kgh_tool COM13 read_stamp -o stamp.bin\n./legic_kgh_tool COM13 write_card 600001 --stamp-file stamp.bin\n```\n\nCommands:\n\n- `read_badge_number` prints the badge number only.\n- `read_info` prints one-line JSON.\n- `read_stamp` prints the stamp as 8 hex chars, or writes raw 4 bytes with `-o/--output-file`.\n- `write_card <badge> (--stamp-file <path> | --stamp-hex <8hex>)` writes the supported KGH layout.\n\nNotes:\n\n- Windows ProxSpace examples use `COM13`.\n- The stamp is 4 bytes and specific to your site.\n  It can be specified as a `.bin` file or as `--stamp-hex` (for example, `003EF417`).\n- You can retrieve the stamp from a supported KGH card with `read_info` or `read_stamp`.\n- Linux examples usually use `/dev/ttyACM0` or similar.\n- `--verbose` can be useful for `read_badge_number` and `write_card`, if they fail for mysterious reasons.\n\n## Building in ProxSpace (for Windows)\n\nDo this in ProxSpace:\n\n```bash\ncd ~/proxmark3/tools/kgh\nrm -rf build-lite\ncmake -G \"MSYS Makefiles\" -S . -B build-lite \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-lite --target legic_kgh_tool -j\nobjdump -p build-lite/legic_kgh_tool.exe | grep -i \"DLL Name\"\n```\n\n## Building Linux\n\n```bash\ncd tools/kgh\nrm -rf build-linux\ncmake -S . -B build-linux \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-linux --target legic_kgh_tool -j\nldd build-linux/legic_kgh_tool\n```\n\n## Static Link Notes\n\n- `legic_kgh_tool` is linked against `pm3rrg_rdv4_static`.\n- On MinGW, CMake adds `-static -static-libgcc` for the target.\n- Linux builds are not the same as the ProxSpace single-EXE deployment.\n- If CMakeCache paths change between ProxSpace and a native shell, delete the build dir and reconfigure.\n","tools/hitag2crack/crack3/README.md":"ht2crack3\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 136 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack3 UID NRARFILE\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\n\n\nTests\n-----\n\nIf you happen to know the key and want to check that all your nR aR values\nare valid (for high-powered demonstrations only, really) then you can use\nthe ht2crack3test program to check them.  It's otherwise massively pointless and a\ncomplete waste of space.\n\n```\n./ht2crack3test NRARFILE KEY UID\n```\n","tools/hitag2crack/crack5/README.md":"ht2crack5\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5 <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n","tools/hitag2crack/crack4/README.md":"ht2crack4\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 16 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack4 -u UID -n NRARFILE [-N nonces to use] [-t table size]\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\nThe number of nonces to use allows you to use less than 32 nonces to increase\nspeed.\nThe table size can be tweaked for speed.  Start with 500000 and double it each\ntime it fails to find the key.\n\n\n","tools/hitag2crack/crack5gpu_disabled/README.md":"ht2crack5gpu\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5gpu <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n","tools/mfc/card_reader/mf_nonce_brute_examples.md":"mf_nonce_brute\n==============\n\nNested autenticated sector key recovery tool\n-----------------------------------------------\n\nCompatible tags:\n* Mifare Classic 1k (4k)\n* Mifare Plus in SL1 mode\n\nTo recover keys to nested autenticated sectors you need a reader-card communication log. To get it use \nhardware tools that able to sniff communication (for example Proxmark3 or HydraNFC).\n\nThis enhanced version:  \nFirst 2 bytes should be bruteforced in phase 2 with mf_key_brute tool that interacts with a card.\n\nSample trace:\n```\n    93 70 fd ac f6 d8 7f 21 4f                            // select card with UID fdacf6d8\nTAG 08 b6 dd                                              // sak\n    60 04 d1 3d                                           // wanna auth block 0x04 with A key\nTAG ed 12 9c 74                                           // 1st auth clear text nt\n    55 53 9f cc 41 8d e8 f3                               // {nr}, {ar}  (nr^ks1, ar^ks2 )\nTAG 05 49 e1 65                                           // {at} ( at^ks3 )\n    03 24 26 56                                           // wanna read block 0x04\nTAG ac 69 ef 58 45 e1 c2 1d a9 47 a5 94 54 ef 5d c7 1e a9 // block 0x04 content\n    d4 3e a8 aa \nTAG 8e 8e e3 e6 e9 e2 5f dd f6 08 ce fb 02 6a db 75 94 2f \n    79 77 68 3c \nTAG e0 00 00 80 80 08 cc 80 08 9c 82 e0 68 64 60 30 91 60  // 18 bytes = 16 byte content + 2 bytes crc\n    ea 88 c3 c2                                            // 4 byte read cmd\nTAG a3 76 dc df c1 42 e0 ee c6 75 a4 ca eb 0c da eb 46 a0  // 18 bytes = 16 byte content + 2 bytes crc ks8 + crc\n    2d 27 ab 6f                                            // wanna auth to 0x04 block with key B\n\n-------Until this line we can recover key or decrypt communication with no troubles (see mfkey64 tool)--------------------------------\n\nTAG 52 6e af 8b                                            // nested auth encrypted tag nonce that we don't know\n    8e 21 3a 29 a4 80 7e 02                                // {nr} = nr^ks1, {ar} = ar^ks2\nTAG b9 43 74 8d                                            // {at} = at^ks3\n    e2 25 f8 32                                            // probably next command (actually is read block cmd, but we don't know it yet)\nTAG 1f 26 82 8d 12 21 dd 42 c2 84 3e d0 26 7f 6b 2a 81 a9  // probably data\n    ba 85 1d 36                                            // probably read cmd\nTAG 62 a8 78 69 ee 36 22 16 1c ff 4b 4e 69 cb 27 c2 e8 7e  // probably data\n    a7 b1 c8 da                                            // probably read cmd\nTAG b2 fc 6c 65 60 ec 35 83 87 56 e3 7e 3c bf 38 b8 73 21  // probably data\n    99 92 13 55                                            // probably read cmd\nTAG 93 5b 65 a3 1d 8c 75 b8 3a 63 e2 31 f0 d0 a9 24 9a f6  // probably data\n```\n\n\nPhase 1\n-------\n\nSyntax:  \n`mf_nonce_brute <uid> <{nt}> <nt_par_err> <{nr}> <{ar}> <ar_par_err> <{at}> <at_par_err> [<{next_command}>]`\n\nExample: if `{nt}` in trace is `8c!  42 e6! 4e!`, then `{nt}` is `8c42e64e` and `nt_par_err` is `1011`\n\nExample with parity (from this trace http://www.proxmark.org/forum/viewtopic.php?pid=550#p550) :\n\n```\n + 561882:  1 :     26\n +     64:  2 : TAG 04  00\n +  10217:  2 :     93  20\n +     64:  5 : TAG 9c  59  9b  32  6c                        UID\n +  12313:  9 :     93  70  9c  59  9b  32  6c  6b  30\n +     64:  3 : TAG 08  b6  dd\n + 923318:  4 :     60  00  f5  7b                            AUTH Block 0\n +    112:  4 : TAG 82  a4  16  6c                            Nonce Tag (nt)\n +   6985:  8 :     a1  e4! 58  ce! 6e  ea! 41  e0!           {nr}, {ar}\n +     64:  4 : TAG 5c! ad  f4  39!                           {at}\n + 811513:  4 :     8e  0e! 5d! b9                            AUTH Block 0 (nested)\n +    112:  4 : TAG 5a! 92  0d! 85!                           Nonce Tag ({nt})\n +   6946:  8 :     98! d7  6b! 77  d6  c6  e8  70            {nr}, {ar}\n +     64:  4 : TAG ca  7e! 0b! 63!                           {at}\n + 670868:  4 :     3e! 70  9c! 8a\n +    112:  4 : TAG 36! 41  24! 79\n +   9505:  8 :     1b! 8c  3a! 48! 83  5a  4a! 27\n +     64:  4 : TAG 40! 6a! 99! 4b\n + 905612:  4 :     c9  7c  64! 13!                           !crc\n +    112:  4 : TAG b5! ab! 1d! 2b\n +   6936:  8 :     7e! d2  5c! ca! 4b! 50! 88! c4            !crc\n +     64:  4 : TAG bf  dd  01  be!\n + 987853:  4 :     56  98  49  d6!                           !crc\n```\n=> Using the plaintext tagnonce `nt`=`82a4166c`\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001 8e0e5db9  \n                 |        |        |     |        |        |    |        |    |\n                 +UID     +nt      |     +{nr}    +{ar}    |    +{at}    |    +{next cmd}\n                                   + nt is clear           +ar_par_err   +at_par_err\n```\n\nWithout a next command, it still finds a possible key candidate.\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85`, it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85` and the encrypted cmd `3e709c8a` to validate , it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\n```\nFull output:\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\nMifare classic nested auth key recovery. Phase 1.\n-------------------------------------------------\nuid:            9c599b32\nnt encrypted:   5a920d85\nnt parity err:  1011\nnr encrypted:   98d76b77\nar encrypted:   d6c6e870\nar parity err:  0000\nat encrypted:   ca7e0b63\nat parity err:  0111\nnext cmd enc:   3e709c8a\n\n\nStarting 4 threads to bruteforce encrypted tag nonce last bytes\nCMD enc(3e709c8a)\n    dec(6000f57b)       <-- Valid cmd\n\nValid Key found: [ffffffffffff]\n\nTime in mf_nonce_brute (Phase 1): 1763 ticks 2.0 seconds\n```\n\n[2024-07-11]\nThere is an odd case where we find multiple valid MIFARE Classic protocol commands with a valid ISO14443-A CRC when decrypting four bytes and are bruteforcing the last upper 16 bit of keyspace in phase 3. \n\nThe command has been updated to give a more informative text in order to help the user understanding and what to do next.\n\n```\n./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n```\n\n\nWhen running you get the following full output\n\n```\n./mf_nonce_brute$ ./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n\nMifare classic nested auth key recovery\n\n----------- information ------------------------\nuid.................. fcf77b54\nnt encrypted......... 1b456bdd\nnt parity err........ 1110\nnr encrypted......... 00f215b6\nar encrypted......... f9eb95e9\nar parity err........ 0011\nat encrypted......... bf55d0b1\nat parity err........ 0000\nnext encrypted cmd... AAD4126B\n\nBruteforce using 8 threads\n\n----------- Phase 1 pre-processing ------------------------\nTesting default keys using NESTED authentication...\n\n----------- Phase 2 examine -------------------------------\nLooking for the last bytes of the encrypted tagnonce\n\nTarget old MFC...\nCMD enc( aad4126b )\n    dec( 302424cf )    <-- valid cmd\n\nKey candidate [ ....37afcc2b ]\nKey candidate [ a70d37afcc2b ]\n\nexecution time 0.47 sec\n\n----------- Phase 3 validating ----------------------------\nuid.................. fcf77b54\npartial key.......... 37afcc2b\npossible key......... a70d37afcc2b\nnt enc............... 1b456bdd\nnr enc............... 00f215b6\nnext encrypted cmd... AAD4126B\n\nLooking for the upper 16 bits of the key\n\nenc:  AAD4126B\ndec:  610BFEDC\n\nValid Key found [ 7c2337afcc2b ]\n\n\nenc:  AAD4126B\ndec:  302424CF\n\nValid Key found [ a70d37afcc2b ] - matches candidate\n\n\nOdd case but we found 2 possible keys\nYou need to test all of them manually, start with the one matching the candidate\n\n```\n\n","tools/hitag2crack/crack5opencl/README.md":"ht2crack5opencl\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5opencl <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n\nUsage:\n\n```\n$ ./ht2crack5opencl\n./ht2crack5opencl [options] {UID} {nR1} {aR1} {nR2} {aR2}\n\nOptions:\n-p     : select OpenCL Platform(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-d     : select OpenCL Device(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-D     : select OpenCL Device Type. 0: GPU, 1: CPU, 2: all. [Default: GPU]\n-S     : select the thread scheduler type. 0: sequential, 1: asynchronous. [Default 1]\n-P     : select the Profile, from 0 to 10. [Default: auto-tuning]\n-F     : force verify key with OpenCL instead of CPU. [Default: disabled]\n-Q     : select queue engine. 0: forward, 1: reverse, 2: random. [Default: 0]\n-s     : show the list of OpenCL platforms/devices, then exit\n-V     : enable debug messages\n-v     : show the version\n-h     : show this help\n```\n\nExample,\n\n```\nsimple\n\n./ht2crack5opencl 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n\nselect devices 1, 2 and 3 using platform 1 and 2, with random queue engine:\n\n./ht2crack5opencl -D 2 -Q 2 -p 1,2 -d 1,2,3 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n```\n\n\nYou can find the correct OpenCL Platform ID (-p) and Device ID (-d) with:\n\n```\n./ht2crack5opencl -s\n```\n","tools/hitag2crack/crack2/README.md":"ht2crack2 suite\n\n\n\nBuild\n-----\n\nEdit ht2crack2buildtable.c and set the DATAMAX, NUM_BUILD_THREADS and NUM_SORT_THREADS values.\nThese are important if you want it to run quickly.  Ideally set DATAMAX to the largest value\nthat you can get away with and set NUM_BUILD_THREADS and NUM_SORT_THREADS to the number of\nvirtual cores you have available, which MUST be a power of 2.  NUM_BUILD_THREADS MUST be >=\nNUM_SORT_THREADS.\n\nCalculate DATAMAX = free RAM available / 65536, and then round down to a power of 10.\n\nThe Makefile is configured for linux.  To compile on Mac, edit it and swap the LIBS= lines.\n\n```\nmake clean\nmake\n```\n\nRun ht2crack2buildtable\n-----------------------\n\nMake sure you are in a directory on a disk with at least 1.5TB of space.\n\n```\n./ht2crack2buildtable\n```\n\nWait a very long time.  Maybe a few days.\n\nThis will create a directory tree called table/ while it is working that will contain\nfiles that will slowly build up in size to approx 20MB each.  Once it has finished making\nthese unsorted files, it will sort them into the directory tree sorted/ and remove the\noriginal files.  It will then exit and you'll have your shiny table.\n\n\nTest with ht2crack2gentests\n---------------------------\n\n```\n./ht2crack2gentests NUMBER_OF_TESTS\n```\n\nto generate NUMBER_OF_TESTS test files.  These will all be named\nkeystream.key-KEYVALUE.uid-UIDVALUE.nR-NRVALUE\n\nTest a single test with\n\n```\n./runtest.sh KEYSTREAMFILE\n```\nor manually with\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n\nor run all tests with\n```\n./runalltests.sh\n```\n\nFeel free to edit the shell scripts to find your tools.  You might want to create a\nsymbolic link to your sorted/ directory called 'sorted' to help ht2crack2seach find the\ntable.\n\nIf the tests work, then the table is sound.\n\n\nSearch for key in real keystream\n--------------------------------\n\nRecover 2048 bits of keystream from the target RFID tag with the RFIDler.  You will have had\nto supply an NR value and you should know the tag's UID (you can get this using the RFIDler).\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n","tools/mfc/card_reader/mfkey_examples.md":"# Card_reader Skill\n\nPath: `tools/mfc/card_reader/mfkey_examples.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/mfc/card_reader/mfkey_examples.md)","tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md":"# OpenCL-Headers Skill\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md)","tools/hitag2crack/common/OpenCL-Headers/README.md":"# OpenCL-Headers Documentation\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/README.md)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md\n\nInstructions for AI coding agents (and humans using one) proposing pull requests\nto this repository. This complements `README.md` and `Maintainers.md`; when in\ndoubt, those human-facing docs win.\n\n## Repo shape (quick map)\n\n- `bootrom/`, `armsrc/` — ARM firmware for the device (Proxmark3\n  hardware targets), buildable via **either** the top-level\n  `Makefile` **or** their respective `CMakeLists.txt`. Keep both build definitions in sync.\n- `client/` — host-side client, buildable via **either** the top-level\n  `Makefile` **or** `client/CMakeLists.txt`. Keep both build definitions in sync.\n- `client/experimental_lib/` — experimental shared-lib build of the client,\n  has its own `CMakeLists.txt`. Any change to the client `client/CMakeLists.txt` almost always implies a change in `client/experimental_lib/CMakeLists.txt`.\n- `common_arm/`, `common/` — shared code between firmware and/or client.\n- `tools/` — standalone tool suites (`hitag2crack`, `mfc/*`, `fpga_compress`,\n  `ePassport`, etc.), each with its own `Makefile` and its own `check` target.\n\n## Before opening a PR: build matrix\n\nDo not treat \"it compiles for me\" as done. For any non-trivial change, verify\nacross the axes below (skip only the ones genuinely unaffected by your diff,\nand say explicitly in the PR description which axes you *did* and *did not*\ntest):\n\n1. **Zero warnings.** `make clean && make all` must complete with no compiler\n   warnings on the default toolchain (gcc). Warnings are effectively treated\n   as errors in this project's normal dev flow.\n2. **Second compiler.** Also try building host client and host tools (if touched) with clang, e.g. `make clean && make client -j CC=clang CXX=clang++ LD=clang++`\n   and fix anything it flags that gcc didn't — clang's\n   diagnostics catch different classes of bugs (e.g. some format-string and\n   sign issues).\n3. **Both client build systems.** If you touched client code, dependencies,\n   or build flags, update and test:\n   - `client/Makefile` (default `make client`)\n   - `client/CMakeLists.txt`\n   - `client/experimental_lib/CMakeLists.txt`\n   A file added to one and not the others is an incomplete PR.\n4. **ARM firmware targets.** If you touched `armsrc/`, `bootrom/`,\n   `common_arm/`, or anything reachable from firmware, compile at least for **both**\n   main platform configs (`PLATFORM=` per `Makefile.platform`): PM3RDV4 and PM5.\n   Use also PLATFORM_EXTRAS if relevant to your changes.\n5. **Cross-OS for platform-sensitive code.** Anything touching serial/USB\n   comms, filesystem paths, threading, or conditional `#ifdef _WIN32` /\n   `__APPLE__` / `__linux__` code needs to at least be reasoned through, and\n   ideally exercised, on all three supported environments: native Linux,\n   Windows (ProxSpace or WSL, per the project's documented Windows build\n   path), and macOS. Say in the PR which of these you actually ran.\n6. **Offline tests.** Run `make check` (or the narrower `<target>/check`,\n   e.g. `client/check`, `armsrc/check`) and make sure it stays green. Add to\n   `tools/pm3_tests.sh` coverage if you're adding a new command/module that\n   can be exercised offline.\n\n### Never `rm -rf` an `obj/` directory\n\nThe ARM-side build has no `mkdir` for its object directories — only the host\nbuild creates its own. `armsrc/obj/`, `armsrc/obj/Standalone/` and\n`bootrom/obj/` exist because each is held open in git by a tracked `.dummy`\nfile, and `make clean` deliberately deletes only the files *inside* them.\nDelete such a directory and nothing recreates it. Every subsequent build dies\nwith messages that give no hint a tracked file went missing:\n\n```\nError. Cannot open output file obj/fpga_all.bit.z\nFatal error: can't create obj/start.o: No such file or directory\n```\n\n`git checkout -- armsrc/obj/.dummy armsrc/obj/Standalone/.dummy bootrom/obj/.dummy`\nputs it back. `git status` showing a deleted `.dummy` is the tell.\n\nIf you script a build matrix, switch `PLATFORM=` / `STANDALONE=` and let make\ndecide what to rebuild — changing those changes the defines, which is enough to\nforce the recompile you want.\n\n## Code style\n\n- Respect the style used in this project: trailing\n  whitespace/EOL cleanup, Equivalent of `astyle` on `*.c`/`*.h` with \n  `--style=google --indent=spaces=4 --indent-switches --keep-one-line-blocks\n  --max-continuation-indent=60 --pad-oper --unpad-paren --pad-header\n  --align-pointer=name` and on `*.cpp`/`*.hpp` (same, minus `--pad-oper`).\n  Don't hand-format C/C++ differently from what `astyle` produces.\n- Don't reformat existing code outside of your changes, only format your own code.\n- If your change adds/changes a client command, run `make commands` to\n  regenerate `doc/commands.md` and `doc/commands.json` — don't hand-edit\n  those generated files.\n- **Keep comments short and direct.** This codebase comments in brief fragments,\n  usually one line. Match the surrounding file. No walls of text. A comment earns\n  its place by saying something the code cannot e.g. a return contract, where a\n  magic number came from, or why something is deliberately absent. Do not restate\n  the code or place commit message content, reasoning, or justification into the\n  source. Anything longer than 3-4 lines usually belongs in the PR instead.\n- **Preserve existing comments** in code you touch or move. Don't drop,\n  \"clean up\", or silently reword neighboring comments as a side effect of an\n  unrelated change.\n- Keep the GPLv3 file header banner (see any existing `.c`/`.h`/`Makefile`)\n  on new files; copy it verbatim from a neighboring file of the same type.\n\n## PR description format\n\nStructure the PR description in these sections:\n\n- **Problem** — what's actually wrong today, with concrete symptoms/examples,\n  not just \"code is messy.\"\n- **Change** — what you did, file by file if it helps a reviewer, and *why*\n  this approach (e.g. why runtime computation instead of a regenerated table).\n- **Behaviour change** — call out explicitly, as its own section, anything a\n  user or downstream code could observe differently after your change, even\n  if the new behavior is strictly more correct. Don't let this hide inside\n  the diff.\n- **Testing** — be specific and be honest:\n  - List the exact build variants exercised, e.g. \"readline (`make`),\n    linenoise (`SKIPREADLINE=1`), CMake client, `experimental_lib` (LIBPM3),\n    `PLATFORM=PM5` and default RDV4.\"\n  - Explicitly state what you did **not** test (e.g. \"Not tested here:\n    Windows/ProxSpace and macOS\") rather than implying full coverage. Where\n    possible, give a one-line reason the untested paths are low-risk (e.g.\n    \"only uses `scandir`/`alphasort`, already used portably elsewhere in\n    `fileutils.c`\").\n  - Net diff size and notable deletions are worth mentioning — removing a\n    stale generated table or dead code is a feature of the PR, not a\n    side note.\n\n## PR checklist (put this in the PR description)\n\n- [ ] Proper style of own code, no unrelated reformatting included\n- [ ] Builds warning-free with gcc; also tried with clang\n- [ ] `client/Makefile`, `client/CMakeLists.txt`, and\n      `client/experimental_lib/CMakeLists.txt` all updated if client sources\n      changed\n- [ ] ARM firmware builds clean for RDV4 and PM5 platform configs (if\n      `armsrc`/`bootrom`/`common_arm` touched)\n- [ ] Platform-sensitive code reasoned about / tested on Linux, Windows\n      (ProxSpace/WSL), and macOS (if applicable) — state which were tested\n- [ ] Existing comments in touched files preserved\n- [ ] New comments short and direct, no restated code or PR prose\n- [ ] `doc/commands.md` / `doc/commands.json` regenerated if commands changed\n\n## Commit attribution\n\nIf an AI agent authored or materially contributed to a commit, say so with a\ntrailer, the same way you'd credit a human co-author, e.g.:\n\n```\nCo-Authored-By: <agent/model name> <noreply@anthropic.com>\n```\n\nDon't omit this to make a PR look purely human-written.\n\n## What not to do\n\n- Don't add `-Werror`-suppressing flags or `#pragma` warning silences to make\n  a warning disappear — fix the underlying issue.\n- Don't introduce a dependency in one client build file without mirroring it\n  in the other two.\n- Don't submit ARM-side changes only test-built for one platform target.\n- Don't `rm -rf` any `obj/` directory to force a rebuild — it deletes tracked\n  `.dummy` files and breaks the build until they are restored. Use `make clean`.\n","isInternal":false,"tokens":2136,"sizeBytes":8415},{"name":"CODE_OF_CONDUCT.md","path":"tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md","title":"OpenCL-Headers Skill","category":"anthropic-skill","format":"markdown","content":"# OpenCL-Headers Skill\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md)","tokens":300,"sizeBytes":247},{"name":"mf_nonce_brute_examples.md","path":"tools/mfc/card_reader/mf_nonce_brute_examples.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/mfc/card_reader/mf_nonce_brute_examples.md","title":"Card_reader Skill","category":"anthropic-skill","format":"markdown","content":"mf_nonce_brute\n==============\n\nNested autenticated sector key recovery tool\n-----------------------------------------------\n\nCompatible tags:\n* Mifare Classic 1k (4k)\n* Mifare Plus in SL1 mode\n\nTo recover keys to nested autenticated sectors you need a reader-card communication log. To get it use \nhardware tools that able to sniff communication (for example Proxmark3 or HydraNFC).\n\nThis enhanced version:  \nFirst 2 bytes should be bruteforced in phase 2 with mf_key_brute tool that interacts with a card.\n\nSample trace:\n```\n    93 70 fd ac f6 d8 7f 21 4f                            // select card with UID fdacf6d8\nTAG 08 b6 dd                                              // sak\n    60 04 d1 3d                                           // wanna auth block 0x04 with A key\nTAG ed 12 9c 74                                           // 1st auth clear text nt\n    55 53 9f cc 41 8d e8 f3                               // {nr}, {ar}  (nr^ks1, ar^ks2 )\nTAG 05 49 e1 65                                           // {at} ( at^ks3 )\n    03 24 26 56                                           // wanna read block 0x04\nTAG ac 69 ef 58 45 e1 c2 1d a9 47 a5 94 54 ef 5d c7 1e a9 // block 0x04 content\n    d4 3e a8 aa \nTAG 8e 8e e3 e6 e9 e2 5f dd f6 08 ce fb 02 6a db 75 94 2f \n    79 77 68 3c \nTAG e0 00 00 80 80 08 cc 80 08 9c 82 e0 68 64 60 30 91 60  // 18 bytes = 16 byte content + 2 bytes crc\n    ea 88 c3 c2                                            // 4 byte read cmd\nTAG a3 76 dc df c1 42 e0 ee c6 75 a4 ca eb 0c da eb 46 a0  // 18 bytes = 16 byte content + 2 bytes crc ks8 + crc\n    2d 27 ab 6f                                            // wanna auth to 0x04 block with key B\n\n-------Until this line we can recover key or decrypt communication with no troubles (see mfkey64 tool)--------------------------------\n\nTAG 52 6e af 8b                                            // nested auth encrypted tag nonce that we don't know\n    8e 21 3a 29 a4 80 7e 02                                // {nr} = nr^ks1, {ar} = ar^ks2\nTAG b9 43 74 8d                                            // {at} = at^ks3\n    e2 25 f8 32                                            // probably next command (actually is read block cmd, but we don't know it yet)\nTAG 1f 26 82 8d 12 21 dd 42 c2 84 3e d0 26 7f 6b 2a 81 a9  // probably data\n    ba 85 1d 36                                            // probably read cmd\nTAG 62 a8 78 69 ee 36 22 16 1c ff 4b 4e 69 cb 27 c2 e8 7e  // probably data\n    a7 b1 c8 da                                            // probably read cmd\nTAG b2 fc 6c 65 60 ec 35 83 87 56 e3 7e 3c bf 38 b8 73 21  // probably data\n    99 92 13 55                                            // probably read cmd\nTAG 93 5b 65 a3 1d 8c 75 b8 3a 63 e2 31 f0 d0 a9 24 9a f6  // probably data\n```\n\n\nPhase 1\n-------\n\nSyntax:  \n`mf_nonce_brute <uid> <{nt}> <nt_par_err> <{nr}> <{ar}> <ar_par_err> <{at}> <at_par_err> [<{next_command}>]`\n\nExample: if `{nt}` in trace is `8c!  42 e6! 4e!`, then `{nt}` is `8c42e64e` and `nt_par_err` is `1011`\n\nExample with parity (from this trace http://www.proxmark.org/forum/viewtopic.php?pid=550#p550) :\n\n```\n + 561882:  1 :     26\n +     64:  2 : TAG 04  00\n +  10217:  2 :     93  20\n +     64:  5 : TAG 9c  59  9b  32  6c                        UID\n +  12313:  9 :     93  70  9c  59  9b  32  6c  6b  30\n +     64:  3 : TAG 08  b6  dd\n + 923318:  4 :     60  00  f5  7b                            AUTH Block 0\n +    112:  4 : TAG 82  a4  16  6c                            Nonce Tag (nt)\n +   6985:  8 :     a1  e4! 58  ce! 6e  ea! 41  e0!           {nr}, {ar}\n +     64:  4 : TAG 5c! ad  f4  39!                           {at}\n + 811513:  4 :     8e  0e! 5d! b9                            AUTH Block 0 (nested)\n +    112:  4 : TAG 5a! 92  0d! 85!                           Nonce Tag ({nt})\n +   6946:  8 :     98! d7  6b! 77  d6  c6  e8  70            {nr}, {ar}\n +     64:  4 : TAG ca  7e! 0b! 63!                           {at}\n + 670868:  4 :     3e! 70  9c! 8a\n +    112:  4 : TAG 36! 41  24! 79\n +   9505:  8 :     1b! 8c  3a! 48! 83  5a  4a! 27\n +     64:  4 : TAG 40! 6a! 99! 4b\n + 905612:  4 :     c9  7c  64! 13!                           !crc\n +    112:  4 : TAG b5! ab! 1d! 2b\n +   6936:  8 :     7e! d2  5c! ca! 4b! 50! 88! c4            !crc\n +     64:  4 : TAG bf  dd  01  be!\n + 987853:  4 :     56  98  49  d6!                           !crc\n```\n=> Using the plaintext tagnonce `nt`=`82a4166c`\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001 8e0e5db9  \n                 |        |        |     |        |        |    |        |    |\n                 +UID     +nt      |     +{nr}    +{ar}    |    +{at}    |    +{next cmd}\n                                   + nt is clear           +ar_par_err   +at_par_err\n```\n\nWithout a next command, it still finds a possible key candidate.\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85`, it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85` and the encrypted cmd `3e709c8a` to validate , it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\n```\nFull output:\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\nMifare classic nested auth key recovery. Phase 1.\n-------------------------------------------------\nuid:            9c599b32\nnt encrypted:   5a920d85\nnt parity err:  1011\nnr encrypted:   98d76b77\nar encrypted:   d6c6e870\nar parity err:  0000\nat encrypted:   ca7e0b63\nat parity err:  0111\nnext cmd enc:   3e709c8a\n\n\nStarting 4 threads to bruteforce encrypted tag nonce last bytes\nCMD enc(3e709c8a)\n    dec(6000f57b)       <-- Valid cmd\n\nValid Key found: [ffffffffffff]\n\nTime in mf_nonce_brute (Phase 1): 1763 ticks 2.0 seconds\n```\n\n[2024-07-11]\nThere is an odd case where we find multiple valid MIFARE Classic protocol commands with a valid ISO14443-A CRC when decrypting four bytes and are bruteforcing the last upper 16 bit of keyspace in phase 3. \n\nThe command has been updated to give a more informative text in order to help the user understanding and what to do next.\n\n```\n./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n```\n\n\nWhen running you get the following full output\n\n```\n./mf_nonce_brute$ ./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n\nMifare classic nested auth key recovery\n\n----------- information ------------------------\nuid.................. fcf77b54\nnt encrypted......... 1b456bdd\nnt parity err........ 1110\nnr encrypted......... 00f215b6\nar encrypted......... f9eb95e9\nar parity err........ 0011\nat encrypted......... bf55d0b1\nat parity err........ 0000\nnext encrypted cmd... AAD4126B\n\nBruteforce using 8 threads\n\n----------- Phase 1 pre-processing ------------------------\nTesting default keys using NESTED authentication...\n\n----------- Phase 2 examine -------------------------------\nLooking for the last bytes of the encrypted tagnonce\n\nTarget old MFC...\nCMD enc( aad4126b )\n    dec( 302424cf )    <-- valid cmd\n\nKey candidate [ ....37afcc2b ]\nKey candidate [ a70d37afcc2b ]\n\nexecution time 0.47 sec\n\n----------- Phase 3 validating ----------------------------\nuid.................. fcf77b54\npartial key.......... 37afcc2b\npossible key......... a70d37afcc2b\nnt enc............... 1b456bdd\nnr enc............... 00f215b6\nnext encrypted cmd... AAD4126B\n\nLooking for the upper 16 bits of the key\n\nenc:  AAD4126B\ndec:  610BFEDC\n\nValid Key found [ 7c2337afcc2b ]\n\n\nenc:  AAD4126B\ndec:  302424CF\n\nValid Key found [ a70d37afcc2b ] - matches candidate\n\n\nOdd case but we found 2 possible keys\nYou need to test all of them manually, start with the one matching the candidate\n\n```\n\n","isInternal":false,"tokens":2826,"sizeBytes":7889},{"name":"mfkey_examples.md","path":"tools/mfc/card_reader/mfkey_examples.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/mfc/card_reader/mfkey_examples.md","title":"Card_reader Skill","category":"anthropic-skill","format":"markdown","content":"# Card_reader Skill\n\nPath: `tools/mfc/card_reader/mfkey_examples.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/mfc/card_reader/mfkey_examples.md)","tokens":300,"sizeBytes":206},{"name":"README.md","path":"tools/deprecated-hid-flasher/flasher/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/deprecated-hid-flasher/flasher/README.md","title":"flasher Documentation","category":"plugin-manifest","format":"markdown","content":"Compilation notes\n=================\n\nBesides the global Proxmark3 requirements, this flasher compatible with very old firmwares requires the libusb 0.1 to work.\nSo you'll need to install the libusb 0.1 package first.\n\n* OSX: libusb-compat\n* Debian-alike: libusb-0.1-4 libusb-dev\n* Arch: libusb\n* Fedora: libusb-devel\n","isInternal":false,"tokens":88,"sizeBytes":317},{"name":"README.md","path":"tools/ePassport/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/ePassport/README.md","title":"ePassport Documentation","category":"plugin-manifest","format":"markdown","content":"# ePassport\n\nAn ePassport (eMRTD) viewer: reads a passport chip through the Proxmark3 and\nrenders it as a passport data page.\n\nEverything runs **offline**. No telemetry, no cloud OCR, no network calls of\nany kind — every font and asset is bundled.\n\n```\n./ePassport.py                                   # normal use\n./ePassport.py --dump DIR                       # open a saved dump, no hardware\n./ePassport.py --dry-run pm3.log --dump DIR     # replay a session you recorded\n./ePassport.py --help\n```\n\n`ePassport.py` is a plain launcher script — run it directly (it has a shebang) or with `python3`, from anywhere, by path or\nfrom a symlink; there is nothing to install and no `PYTHONPATH` to set. If a\ndependency is missing it says which one, which interpreter it used, and the\nexact command to fix it.\n\nIt needs an interpreter that has the requirements. With a virtualenv, either\nactivate it first or point at it directly:\n\n```bash\n/path/to/venv/bin/python ./ePassport.py\n```\n\n---\n\n## Install\n\n```bash\npython3 -m pip install -r requirements.txt\n```\n\nKivy is required. Everything else is optional and the app degrades with a\nmessage telling you what to install:\n\n| Missing | What stops working |\n|---|---|\n| `opencv-python-headless` | the Scan screen (camera) |\n| `pytesseract` + the `tesseract-ocr` binary | MRZ OCR — manual entry still works |\n| `Pillow` / `glymur` | portrait decoding (DG2 is usually JPEG2000) |\n| `asn1crypto` / `cryptography` | EF_SOD inspection and the DG hash table |\n\nFor the best OCR accuracy install the OCR-B or `mrz` traineddata; the app picks\nit up automatically and falls back to `eng` with a character whitelist.\n\n`sudo apt install xclip` enables Kivy's cut-buffer support. The app filters\nthe noisy `[CRITICAL] [Cutbuffer]` complaint either way; nothing depends on it.\n\n## Relationship to proxmark3\n\nThis app **does not modify the proxmark3 tree**. The only coupling is the `pm3`\nCLI, invoked in one-shot command mode:\n\n```\npm3 -c \"hf emrtd dump -n <DOCNUM> -d <YYMMDD> -e <YYMMDD> --dir <outdir>\"\npm3 -c \"hf emrtd info --dir <existing dump>\"     # offline mode\n```\n\nThe binary is located via `$PM3_BIN` → the configured path → `PATH` → `~/pm3/pm3`\n→ the `./pm3` wrapper of an enclosing proxmark3 source tree.\n\nThe country-name table in `emrtd/countries.py` is **generated** from the\nproxmark3 client's own ISO-3166 table (`fdxbCountryMapping` in\n`client/src/cmdlffdxb.c`). Regenerate it with:\n\n```bash\npython3 tools_gen_countries.py ../../client/src/cmdlffdxb.c\n```\n\n### Authentication\n\n| You have | Enter | What runs |\n|---|---|---|\n| The MRZ | document number + both dates, or line 2 | PACE with the MRZ, falling back to BAC |\n| The CAN | the number printed on the data page | `--can` (PACE only) |\n\nThe **CAN** is the short number printed on the data page — usually 6 digits.\nIt is a PACE password, so it is mutually exclusive with the MRZ, and BAC can\nnever use it. The Authentication dropdown forces `--pace` or `--bac` when you\nwant to test one path; leave it on Automatic otherwise.\n\nWrong CANs are counted by the chip and the password will eventually block, so\nthat failure is called out separately from a wrong MRZ.\n\n### Two things worth knowing about `hf emrtd`\n\n- **All three of `-n/-d/-e` must be supplied**, or the client silently drops to\n  no-BAC mode and fails on any protected passport. The app refuses a partial\n  triple rather than passing it on.\n- **The `pm3` wrapper blocks forever** waiting for a device when none is\n  attached. The app watches for that line and reports \"No Proxmark3 found\"\n  immediately instead of sitting on the timeout.\n\n## Using it\n\n1. **Scan** the MRZ with a camera, or **type** the three values. A full 44-char\n   MRZ line 2 takes precedence and is passed as `-m`, which avoids\n   field-splitting mistakes.\n2. **Read** — pm3 runs on a worker thread and streams into the LOG tab, with a\n   determinate progress bar and a Cancel that actually kills the process.\n3. The dump is parsed from the **binaries** (BER-TLV), never scraped from\n   `hf emrtd info` stdout, and rendered as a data page.\n\nTabs across the top: `DATA PAGE` · `PERSONAL` (DG11) · `ISSUER` (DG12) ·\n`SECURITY` (SOD/DG14/DG15) · `FILES` · `LOG`.\n\n### Output\n\nThe app is quiet by default. Kivy 2.3 takes its log level from\n`~/.kivy/config.ini`, which is shared with every other Kivy app on the machine,\nso rather than rewrite that the app drops Kivy's console handler and installs\nits own for warnings and above. pytesseract (which logs a full tesseract\ncommand line per frame), OpenCV and its V4L2 backend are quietened the same\nway. `-v` puts all of it back.\n\n### Resizing\n\nThe page is laid out **once** at a fixed resolution and then drawn scaled, so a\nresize costs a matrix multiply rather than a full re-flow. Re-flowing it on\nevery resize event re-rendered every label and regenerated the security print\nseveral times a frame, which made dragging a window edge crawl and the contents\njitter as text reflowed under the cursor.\n\nMeasured over twenty resize steps:\n\n| | Before | After |\n|---|---|---|\n| Page widget redraws per step | 21 | 0 |\n| Label re-renders per step | 65 | 11 (window chrome only) |\n| Time in text rendering | 182 ms | 10 ms |\n\nTwo supporting fixes: redraws are coalesced onto a `Clock` trigger so `pos` and\n`size` changing separately cannot cause three redraws in one frame, and MRZ\nglyphs are cached per (character, size) — an MRZ is ~90 characters drawn from\nan alphabet of 37, so it was building ninety textures to show at most\nthirty-seven distinct ones.\n\n### Why a document may not fill the window\n\nBoth formats are always scaled as large as they fit without distorting, so\nneither is ever \"shrunk\" — but a document and a window are different shapes,\nand only one of the two dimensions can fill. Whichever document is closer to\nthe window's shape uses more of it:\n\n| Window content shape | Passport (1.42) | Card (1.59) |\n|---|---|---|\n| 1.61 (wide) | 88% wide, 100% tall | 99% wide, 100% tall |\n| 1.42 (the default) | **100% wide, 100% tall** | 100% wide, 90% tall |\n| 2.59 (very wide) | 55% wide, 100% tall | 61% wide, 100% tall |\n\nThe default window is sized so its **content area comes out at the reference\ndocument's own 125:88**, so a passport fills it exactly on first run. Stretch\nthe window wide and both documents will letterbox at the sides; that is the\nshape mismatch, not the app giving up on the space.\n\n### Small windows\n\nThe minimum window is 760x520 and the app remembers the size you leave it at.\nEverything is built to survive that:\n\n- the passport page scales as a unit and keeps its aspect;\n- the tab strip shares its width rather than claiming fixed slots;\n- the FILES table uses proportional columns, so the state column does not fall\n  off the edge;\n- the hex viewer fits **16, 8 or 4 bytes per row** to whatever width the pane\n  has, because a hex dump must not wrap.\n\n### Speed\n\nAn MRZ scan settles in roughly a second. What that took:\n\n| Change | Effect |\n|---|---|\n| Cheap pre-gate before OCR (`looks_like_text`) | a badly framed strip costs ~0.3 ms instead of ~400 ms |\n| Skip frames already processed | no repeat OCR of an identical frame |\n| Pace the loop instead of adding to it | the interval no longer stacks on top of the work |\n| Cache the language lookup | it shelled out to tesseract every frame |\n| Stop escalating variants with no signal | 2 passes instead of 3 on hopeless frames |\n| Remember the last winning variant | dim lighting costs 1 pass, not 3 |\n\nMeasured on a live camera: mean OCR pass 381 ms → 163 ms, time to acceptance\n3.1 s → 1.3 s, with accuracy unchanged on the synthetic bench.\n\nThe gate runs *after* deskew — it measures horizontal bands of ink, and tilted\ntext smears those bands together.\n\nAn in-process binding (`tesserocr`) is ~3× faster per call than re-launching\nthe tesseract binary, and was tried. It is **not** used: the PyPI wheel bundles\nits own leptonica, and pairing that with a system `tessdata` directory hung\nindefinitely mid-recognition. A backend that can wedge the OCR thread is worse\nthan a slower one.\n\n### Cameras\n\nThe Scan screen enumerates capture devices by name from\n`/sys/class/video4linux` — without opening them, because opening a device is\ndisruptive if something else is using it.\n\n- **No camera**: the screen says so and offers **Rescan for devices**. Manual\n  entry is always available and works just as well.\n- **One or more**: a dropdown lists them by name (`0: IPEVO Ziggi-HD Plus`).\n  The choice is remembered.\n\nLinux commonly exposes several `/dev/videoN` nodes for one physical camera,\nonly one of which delivers frames — `isOpened()` returns true for the others.\nThe app therefore treats a successful *read* as the test, and falls back to a\nneighbouring index automatically. **Rescan** probes every device to label the\ndead ones `(no frames)`; it stops the preview first so the probe and the\ncapture thread do not fight over the device.\n\nOnly line 2 is needed for BAC, so the scan accepts a lone line 2 when its five\ncheck digits — composite included — all pass.\n\n### What a \"valid\" MRZ scan does and does not prove\n\nA scan is accepted only when every check digit validates **and** two\nconsecutive frames agree. That still does not prove the document number is\nright. The 7-3-1 checksum is taken modulo 10 and its weights are coprime with\n10, so swapping a character for one whose value differs by a multiple of 10\nleaves every check digit — composite included — unchanged. The blind pairs are\n`L`/`1`, `S`/`8`, `G`/`6`, `Z`/`5`, `I`/`8`, `D`/`3` … which are exactly the\nswaps OCR is most likely to make.\n\nThat is why a scan **fills the entry form and stops** rather than starting a\nread, and why the form flags the document number for a second look. If BAC\nthen fails, the document number is the first thing to check.\n\n(Confusions that are *not* blind, such as `O` read as `0` in a country code,\nare repaired automatically by position before validation.)\n\n### Drawing the page\n\nA TD1 is an ID-1 card (85.6 x 54 mm), not a small passport data page\n(125 x 88 mm), and its three-line MRZ takes about a quarter of its height\nagainst an eighth for a passport's two lines. The page is drawn at whichever\nshape the document really is.\n\n**Two scale modes**, because you cannot have both at once. OCR-B is a fixed\n2.54 mm pitch on every format, but a character is 2.97% of a card's width and\nonly 2.03% of a passport's — so a card's MRZ is inherently half again as large\nrelative to its own document:\n\n| Mode | What it gives you | What it costs |\n|---|---|---|\n| **Fit window** (default) | every document fills the window | a card's MRZ prints ~1.5x a passport's on screen |\n| **True size** | MRZ print identical across formats, as in the hand | a card is drawn two thirds the width, leaving margins |\n\nOpening a dump re-fits the page for whatever format it turns out to be, so the\nbutton is a preference you set once, not something to press after every load.\nThe toolbar button swaps them and the choice is remembered. It is labelled\nwith the **action**, like the chrome button beside it: reading \"Fit window\"\nmeans clicking will fit the window, so you are currently at true size. A\npassport looks identical either way; only formats smaller than the reference\npage differ.\n\nWithin the band, the MRZ block is sized to fit in **both** directions — the\nsmaller of the width- and height-derived sizes wins, and a block that does not\nfill the width is centred. Fitting the width alone pushed a card's MRZ out over\nthe fields above it; leaving a full line of air between rows then shrank it\nuntil it no longer reached the margins.\n\nThe **portrait** is sized from the page width and the real 35 x 45 photo shape,\ncapped against the space above the band — a fraction of page height alone made\nit swallow a short card. The frame keeps the photo aspect whichever constraint\nbinds, so an image never sits letterboxed in white bars.\n\nThe guilloche is generated procedurally (superimposed hypotrochoids at low\nalpha) — nothing is traced from a real document's security print. It is clipped\nto the printed frame **geometrically**, with a Liang-Barsky segment clip, not\nwith a stencil: this widget can sit inside another `StencilView`, and Kivy's\nnested stencils do not intersect, so an inner stencil silently stops clipping\nanything. That bug had the pattern spilling past the page edge onto the\nwindow background.\n\nText over the pattern measures about 15:1 contrast, well clear of the 4.5:1\nfloor.\n\n### Fields that may not be there\n\nDG11 and DG12 are optional and plenty of real passports omit them entirely —\nplace of birth, date of issue and issuing authority are printed on the page but\nnever written to the chip. Those fields say **\"not on chip\"** rather than\nshowing an empty value, so a missing data group is not mistaken for a parse\nfailure.\n\nThe **personal number** is recovered from the MRZ optional-data field when\nDG11 is absent — several states, Sweden among them, put the national identity\nnumber there. The field's caption says `PERSONAL No. (FROM MRZ)` when it came\nfrom that fallback.\n\n### What the SECURITY tab does and does not check\n\nIt hashes each dumped data group and compares against the hash table inside\nEF_SOD, marking every DG **match / MISMATCH / not checked**. It does **not**\nvalidate the signer certificate chain — that needs the issuing country's CSCA\ncertificate, which the app deliberately does not fetch.\n\n## Where your reads go\n\nEvery read writes to:\n\n```\n~/.local/share/ePassport/dumps/<UTC-timestamp>/\n```\n\ncreated `0700`. The app was previously called `pm3-passport`; if a directory\nof that name exists it is moved to the new one on first run, so earlier reads\nare carried across rather than orphaned. You do not need to remember that: **Dumps…** in the toolbar\nlists every read with its timestamp and contents. From there you can open one,\ndelete one with the bin button, open the folder in your file manager, or clear\nout the empty directories left behind by reads that failed. The path is also in\nthe status bar (click it) and in the log at the start of every read.\n\nEvery read also leaves `pm3.log` in its directory: the client output for that\nrun, which is the only record of why a read that dumped nothing gave up. It\nholds what the LOG pane showed and not the MRZ or CAN you typed, and it does\nnot count as a file when the app decides whether a read produced anything.\n\nDeleting always asks first, and says what it is about to destroy — a dump holds\na real portrait and a real MRZ.\n\n**Opening a dump from elsewhere** (a colleague's, or the generated samples):\n**Dumps… → Samples…** goes straight to `./samples`, and **Browse…** opens a\npicker with one-click jumps to **Recent**, **Dumps**, **Samples**, **Working\ndir** and **Home**, plus a path box you can type or paste into.\n\nThe picker reopens **beside the last dump you loaded**, so picking a second\ndump next to the first does not mean navigating there again. Shortcuts that do\nnot exist are not shown — `Samples` only appears once you have generated them —\nand duplicates collapse, so `Recent` and `Samples` do not both appear when they\nare the same folder.\n\n## Your data\n\n- Dumps are `0700` and there is a **Delete dump** button.\n- MRZ values and document numbers are never written outside that directory.\n- \"Remember\" on the entry screen defaults to **off** — those values are live\n  credential material.\n- The app is strictly read-only: it displays what the chip returns, and no\n  field is editable.\n\n## Development\n\n```bash\nmake test              # 297 tests, no hardware needed\nmake samples           # generate the fabricated dumps into ./samples\nmake clean             # drop __pycache__ and the test cache\nmake distclean         # the above, plus the generated samples\nmake format            # reformat with black\nmake help              # the rest\n```\n\nThe proxmark3 root `Makefile` recurses in here too, following the same pattern\nit uses for `hitag2crack`:\n\n```bash\nmake ePassport/clean     # from the repository root\nmake ePassport/test\nmake ePassport/help\n```\n\nePassport is deliberately **not** in the root `TARGETS`, so a plain `make` or\n`make clean` at the top level does not touch it — it builds nothing and is not\npart of the firmware or client build.\n\n`make` shells out to `python3`; if your dependencies live in a virtualenv,\npoint it at that interpreter:\n\n```bash\nmake test PYTHON=/path/to/venv/bin/python\n```\n\nThe same without `make`:\n\n```bash\npython3 -m pytest tests/ -q\npython3 tools_make_sample.py [DIR]              # generate the sample dumps\npython3 -m epassport.emrtd samples/td3_utopia   # headless: parse and print\npython3 -m black epassport tests tools_*.py\n```\n\n### Nothing derived from a document is checked in\n\nThis tree carries **no dumps, no logs and no images**. A dump holds a live\nportrait and MRZ, and a screenshot of one is just as identifying — so none of\nit belongs in version control, not even the fabricated kind, and `.gitignore`\nrefuses the file types outright.\n\nWhat you need instead is generated:\n\n```bash\npython3 tools_make_sample.py [DIR]      # fabricated dumps, default ./samples\n```\n\nThey are documents of the fictional ICAO specimen state \"Utopia\": no real\npersonal data, no real security print. `td3_utopia` carries a genuinely signed\nEF_SOD, `td3_utopia_tampered` is the same document with DG2 swapped after\nsigning so the SECURITY tab has a MISMATCH to show, and `td1_utopia_idcard` is\na TD1 card with no DG11/DG12 or SOD.\n\nThe tests never touch that directory: `tests/conftest.py` builds its own copy\ninto a temporary directory, and the recorded pm3 sessions used by the\n`--dry-run` tests are inline in `tests/test_pm3_client.py`.\n\nTo replay a real session, record it yourself:\n\n```bash\npm3 -c \"hf emrtd dump -n ... -d ... -e ...\" | tee pm3.log\n```\n\n### Layout\n\n```\nMakefile             run / test / format / clean\nePassport.py         the launcher; everything below is the implementation\nepassport/\n  app.py               app, screens, worker threads\n  __main__.py          shim so `python3 -m epassport` still works\n  config.py            paths, settings, 0700 data dir\n  pm3/client.py        subprocess, streaming, cancel, timeout\n  pm3/errors.py        typed failures + plain-English remedies\n  emrtd/tlv.py         BER-TLV reader\n  emrtd/mrz.py         TD1/TD2/TD3, check digits, date window\n  emrtd/dg.py          per-DG decoders -> PassportRecord\n  emrtd/sod.py         optional CMS/SOD inspection\n  emrtd/images.py      JPEG/JP2 carving out of CBEFF blobs\n  emrtd/model.py       PassportRecord: the single UI-facing object\n  ocr/                 camera thread, OCR pipeline, accept rule\n  ui/                  Kivy widgets and .kv files\n```\n\n**Threading contract:** the pm3 subprocess, file parsing, image decoding and\nOCR all run off the main thread; UI mutation happens only via\n`Clock.schedule_once`. The app never freezes while a dump runs.\n\n**Single source of truth:** every parser produces one `PassportRecord`, and the\nUI binds only to that — which is why \"open saved dump\" and \"read from card\" are\nthe same rendering path.\n","isInternal":false,"tokens":4872,"sizeBytes":19140},{"name":"README.md","path":"tools/hitag2crack/common/OpenCL-Headers/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/README.md","title":"OpenCL-Headers Documentation","category":"plugin-manifest","format":"markdown","content":"# OpenCL-Headers Documentation\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/README.md)","tokens":300,"sizeBytes":237},{"name":"README.md","path":"tools/hitag2crack/crack2/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/crack2/README.md","title":"crack2 Documentation","category":"plugin-manifest","format":"markdown","content":"ht2crack2 suite\n\n\n\nBuild\n-----\n\nEdit ht2crack2buildtable.c and set the DATAMAX, NUM_BUILD_THREADS and NUM_SORT_THREADS values.\nThese are important if you want it to run quickly.  Ideally set DATAMAX to the largest value\nthat you can get away with and set NUM_BUILD_THREADS and NUM_SORT_THREADS to the number of\nvirtual cores you have available, which MUST be a power of 2.  NUM_BUILD_THREADS MUST be >=\nNUM_SORT_THREADS.\n\nCalculate DATAMAX = free RAM available / 65536, and then round down to a power of 10.\n\nThe Makefile is configured for linux.  To compile on Mac, edit it and swap the LIBS= lines.\n\n```\nmake clean\nmake\n```\n\nRun ht2crack2buildtable\n-----------------------\n\nMake sure you are in a directory on a disk with at least 1.5TB of space.\n\n```\n./ht2crack2buildtable\n```\n\nWait a very long time.  Maybe a few days.\n\nThis will create a directory tree called table/ while it is working that will contain\nfiles that will slowly build up in size to approx 20MB each.  Once it has finished making\nthese unsorted files, it will sort them into the directory tree sorted/ and remove the\noriginal files.  It will then exit and you'll have your shiny table.\n\n\nTest with ht2crack2gentests\n---------------------------\n\n```\n./ht2crack2gentests NUMBER_OF_TESTS\n```\n\nto generate NUMBER_OF_TESTS test files.  These will all be named\nkeystream.key-KEYVALUE.uid-UIDVALUE.nR-NRVALUE\n\nTest a single test with\n\n```\n./runtest.sh KEYSTREAMFILE\n```\nor manually with\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n\nor run all tests with\n```\n./runalltests.sh\n```\n\nFeel free to edit the shell scripts to find your tools.  You might want to create a\nsymbolic link to your sorted/ directory called 'sorted' to help ht2crack2seach find the\ntable.\n\nIf the tests work, then the table is sound.\n\n\nSearch for key in real keystream\n--------------------------------\n\nRecover 2048 bits of keystream from the target RFID tag with the RFIDler.  You will have had\nto supply an NR value and you should know the tag's UID (you can get this using the RFIDler).\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n","isInternal":false,"tokens":543,"sizeBytes":2095},{"name":"README.md","path":"tools/hitag2crack/crack3/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/crack3/README.md","title":"crack3 Documentation","category":"plugin-manifest","format":"markdown","content":"ht2crack3\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 136 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack3 UID NRARFILE\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\n\n\nTests\n-----\n\nIf you happen to know the key and want to check that all your nR aR values\nare valid (for high-powered demonstrations only, really) then you can use\nthe ht2crack3test program to check them.  It's otherwise massively pointless and a\ncomplete waste of space.\n\n```\n./ht2crack3test NRARFILE KEY UID\n```\n","isInternal":false,"tokens":212,"sizeBytes":725},{"name":"README.md","path":"tools/hitag2crack/crack4/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/crack4/README.md","title":"crack4 Documentation","category":"plugin-manifest","format":"markdown","content":"ht2crack4\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 16 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack4 -u UID -n NRARFILE [-N nonces to use] [-t table size]\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\nThe number of nonces to use allows you to use less than 32 nonces to increase\nspeed.\nThe table size can be tweaked for speed.  Start with 500000 and double it each\ntime it fails to find the key.\n\n\n","isInternal":false,"tokens":195,"sizeBytes":648},{"name":"README.md","path":"tools/hitag2crack/crack5/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/crack5/README.md","title":"crack5 Documentation","category":"plugin-manifest","format":"markdown","content":"ht2crack5\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5 <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n","isInternal":false,"tokens":104,"sizeBytes":301},{"name":"README.md","path":"tools/hitag2crack/crack5gpu_disabled/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/crack5gpu_disabled/README.md","title":"crack5gpu_disabled Documentation","category":"plugin-manifest","format":"markdown","content":"ht2crack5gpu\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5gpu <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n","isInternal":false,"tokens":130,"sizeBytes":423},{"name":"README.md","path":"tools/hitag2crack/crack5opencl/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/crack5opencl/README.md","title":"crack5opencl Documentation","category":"plugin-manifest","format":"markdown","content":"ht2crack5opencl\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5opencl <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n\nUsage:\n\n```\n$ ./ht2crack5opencl\n./ht2crack5opencl [options] {UID} {nR1} {aR1} {nR2} {aR2}\n\nOptions:\n-p     : select OpenCL Platform(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-d     : select OpenCL Device(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-D     : select OpenCL Device Type. 0: GPU, 1: CPU, 2: all. [Default: GPU]\n-S     : select the thread scheduler type. 0: sequential, 1: asynchronous. [Default 1]\n-P     : select the Profile, from 0 to 10. [Default: auto-tuning]\n-F     : force verify key with OpenCL instead of CPU. [Default: disabled]\n-Q     : select queue engine. 0: forward, 1: reverse, 2: random. [Default: 0]\n-s     : show the list of OpenCL platforms/devices, then exit\n-V     : enable debug messages\n-v     : show the version\n-h     : show this help\n```\n\nExample,\n\n```\nsimple\n\n./ht2crack5opencl 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n\nselect devices 1, 2 and 3 using platform 1 and 2, with random queue engine:\n\n./ht2crack5opencl -D 2 -Q 2 -p 1,2 -d 1,2,3 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n```\n\n\nYou can find the correct OpenCL Platform ID (-p) and Device ID (-d) with:\n\n```\n./ht2crack5opencl -s\n```\n","isInternal":false,"tokens":554,"sizeBytes":1582},{"name":"README.md","path":"tools/hitag2crack/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/README.md","title":"hitag2crack Documentation","category":"plugin-manifest","format":"markdown","content":"HiTag2 Cracking Suite\n---------------------\n\nAuthors:\n\n* Attacks 1, 2, 3, 4 : Kevin Sheldrake <kev@headhacking.com>\n* Attacks 5, 5gpu : anonymous, based on https://github.com/factoritbv/hitag2hell by FactorIT B.V.\n* Attack  5opencl : Gabriele Gristina <gabriele.gristina@gmail.com>, based on 5gpu\n\nIntroduction\n------------\n\nThese tools are implementations of the four attacks detailed in the papers,\nGone In 360 Seconds - Hijacking With HiTag 2 by Roel Verdult, Flavio Garcia\nand Josep Balasch, and Lock It And Still Lose It - on the (In)Security of\nAutomotive Remote Keyless Entry Systems by Flavio Garcia, David Oswald,\nTimo Kasper and Pierre Pavlides.  The first three attacks come from the first\npaper and the fourth attack comes from the second paper.\n\n\n_note_\nThere are no Proxmark3 client implemented commands for these attacks. Only separate executables to be compiled and run on your own system.\nNo guarantees of working binaries on all systems.  Some work on linux only. \nThere is no easy way to extract the needed data from a live system and use with these tools.\nYou can use the `RFIdler` device but the Proxmark3 client needs some more love.  Feel free to contribute.\n\nAttack 1\n--------\n\nAttack 1 is a nonce replay and length extension attack.  This is an attack on\na single HiTag2 RFID tag, given a single encrypted nonce and challenge\nresponse value pair (nR, aR) for the tag's UID.  The attack runs entirely on\nthe Proxmark3 with it acting like a RWD that replays the same encrypted nonce\nand challenge response pair for every interaction; this fixes the key stream\nthat the tag's PRNG outputs to the same stream for every interaction.\n\nBy brute forcing a subset of the encrypted command space, the Proxmark3 finds a\nsingle valid encrypted command - invalid commands return a known unencrypted\nerror response so finding a valid one is simply a case of trying different\nvalues until a response other than the error response is received.\n\nIt then bit flips the valid encrypted command to find the other 15 valid\nencrypted commands.  By knowing the contents of page 0 - it's the UID that\nis presented in clear at the start of each interaction - it tries each\nencrypted response in turn, assuming each to be the encrypted version of\n'read page 0 non-inverted' and each response to be the encrypted version of\npage 0.\n\nFor each attempted command, it calculates the key stream that would have\ncorrectly generated the encrypted command and response:\ncommand ++ response XOR key stream = encrypted command ++ encrypted response\ntherefore:\nkey stream = command ++ response XOR encrypted command ++ encrypted response\n\nIt then tests the potentially recovered key stream by creating an encrypted\ncommand that consumes as much of it as possible, re-initialising with the same\nencrypted nonce and challenge response pair (to set the key stream to the\nsame stream as that which produced the encrypted command response it is\ntesting), and then sending this extended encrypted command.  If the response\nis not the error response, then the key stream is valid and the response is\nthe encryption of the page 0 contents (the UID).\n\nWhen one of the valid encrypted commands satisfies this situation, the\nrecovered key stream must be the output of the PRNG for the given encrypted\nnonce and challenge response pair.\n\nThe Proxmark3 then uses this key stream to encrypt commands and decrypt the\nresponses, and therefore requests the contents of all 8 pages.  Pages 1 and 2\ncontain the encryption key.\n\nAttack 2\n--------\n\nAttack 2 is a time/space trade off to recover the key for situations where the\ntag has been configured to prevent reading of pages 1 and 2.  This attack uses\na pre-computed table of 2^37 PRNG states and resultant PRNG output, sorted on\nthe PRNG output.  The Proxmark3 is used to recover 2048 bits of key stream using\na modification of attack 1 and this is used to search the table for matching\nPRNG output.  When the output is found, it is tested for validity (by testing\nprevious or following PRNG output) and then the PRNG state is rolled back to\nthe initialisation state, from which the unencrypted nonce and key can be\nrecovered.\n\nAttack 3\n--------\n\nAttack 3 is a cryptanalytic attack that focuses on the RWD and a bias in the\nPRNG output.  By capturing 136 encrypted nonce and challenge response pairs,\ncandidates for the first 34 bits of the key can be identified, and for each\nthe remaining 14 bits can be brute forced.\n\nAttack 4\n--------\n\nAttack 4 is a fast correlative attack on the key based on a number of captured\nencrypted nonce and challenge response pairs (up to 32, but 16 usually\nsufficient).  It starts by guessing the first 16 bits of the key and scores\nall these guesses against how likely they are to be the correct key, given the\nencrypted nonces and the keystream they should produce.  Each guess is then\nexpanded by 1 bit and the process iterates, with only the best guesses taken\nforward to the next iteration.\n\nAttack 5\n--------\n\nAttack 5 is heavily based on the HiTag2 Hell CPU implementation from https://github.com/factoritbv/hitag2hell by FactorIT B.V.,\nwith the following changes:\n\n* Main takes a UID and 2 {nR},{aR} pairs as arguments and searches for states producing the first aR sample, reconstructs the corresponding key candidates and tests them against the second nR,aR pair;\n* Reuses the Hitag helping functions of the other attacks.\n\nAttack 5gpu\n-----------\n\nAttack 5gpu is identical to attack 5, simply the code has been ported to OpenCL\nto run on GPUs and is therefore much faster than attack 5.\n\nAttack 5opencl\n--------------\n\nAttack 5opencl is an optimized OpenCL version based on 5gpu.\nIt runs on multi GPUs/CPUs and is faster than 5gpu.\n\nUsage details: Attack 1\n-----------------------\n\nAttack 1 requires a valid tag and a valid encrypted nonce and challenge\nresponse pair.  The attacker needs to obtain a valid tag and then use this to\nobtain a valid encrypted nonce and challenge response pair.  This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.   \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** example\n\n\nUsage details: Attack 2\n-----------------------\n\nAttack 2 requires the same resources as attack 1, plus a pre-computed table.\nThe table can be generated on a disk with >1.5TB of storage, although it takes\nsome time (allow a couple of days, privilege SSD). This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.  \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\n./ht2crack2gentest 1\n./runalltests.sh\n```\n\nUsage details: Attack 3\n-----------------------\n\nAttack 3 requires only interaction with the RWD and does not require a valid\ntag, although it does require a HiTag2 tag that the RWD will initially respond\nto; e.g. you could potentially use any HiTag2 tag as long as the RWD starts\nthe crypto handshake with it.  It requires >=136 encrypted nonce and challenge\nresponse pairs for the same tag UID.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** will be ht2 sim or sniff with actual tag ?\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py 000102030405 AABBCCDD 32 > hitag2_AABBCCDD_nrar_32emul.txt\n./ht2crack3test hitag2_AABBCCDD_nrar_32emul.txt 000102030405 AABBCCDD\n./ht2crack3 AABBCCDD hitag2_AABBCCDD_nrar_32emul.txt |grep -E -v '(trying|partial)'\nrm hitag2_AABBCCDD_nrar_32emul.txt\n```\n\nUsage details: Attack 4\n-----------------------\n\nAttack 4 requires the same information as attack 3, but only 16-32 encrypted\nnonce and challenge response pairs are required.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py AABBCCDDEEFF 12345678 32 > hitag2_12345678_nrar_32emul.txt\n./ht2crack4 -u 12345678 -n hitag2_12345678_nrar_32emul.txt -N 16 -t 500000 2>&1\nrm hitag2_12345678_nrar_32emul.txt\n```\n\nUsage details: Attack 5\n-----------------------\n\nAttack 5 requires two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5 12345678 71DA20AA 7EFDF3FA 2A4265F9 59653B07\n```\n\nUsage details: Attack 5gpu/5opencl\n----------------------------------\n\nAttacks 5gpu and 5opencl require two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5opencl 12345678 B438220C 944FFD74 942C59E3 3D450B34\n```\n\n5opencl supports a number of additional parameters, see [crack5opencl/README.md](/tools/hitag2crack/crack5opencl/README.md) for details.\n\nUsage details: Next steps\n-------------------------\n\nOnce the key has been recovered using one of these attacks, the Proxmark3 can\nbe configured to operate as a RWD and will capture tags using that key.\n\n**TODO** example\n\nTags can be copied with standard Proxmark3 commands.\n\n**TODO** example\n","isInternal":false,"tokens":2315,"sizeBytes":9160},{"name":"README.md","path":"tools/kgh/README.md","rawUrl":"https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/kgh/README.md","title":"kgh Documentation","category":"plugin-manifest","format":"markdown","content":"# legic_kgh_tool\n\n## Running\n\n`legic_kgh_tool` reads KGH LEGIC card information, badge numbers, and stamps,\nand writes the supported KGH card layout.\n\nExamples:\n\n```bash\n./legic_kgh_tool COM13 read_badge_number\n./legic_kgh_tool COM13 read_info\n./legic_kgh_tool COM13 read_stamp\n./legic_kgh_tool COM13 read_stamp -o stamp.bin\n./legic_kgh_tool COM13 write_card 600001 --stamp-file stamp.bin\n```\n\nCommands:\n\n- `read_badge_number` prints the badge number only.\n- `read_info` prints one-line JSON.\n- `read_stamp` prints the stamp as 8 hex chars, or writes raw 4 bytes with `-o/--output-file`.\n- `write_card <badge> (--stamp-file <path> | --stamp-hex <8hex>)` writes the supported KGH layout.\n\nNotes:\n\n- Windows ProxSpace examples use `COM13`.\n- The stamp is 4 bytes and specific to your site.\n  It can be specified as a `.bin` file or as `--stamp-hex` (for example, `003EF417`).\n- You can retrieve the stamp from a supported KGH card with `read_info` or `read_stamp`.\n- Linux examples usually use `/dev/ttyACM0` or similar.\n- `--verbose` can be useful for `read_badge_number` and `write_card`, if they fail for mysterious reasons.\n\n## Building in ProxSpace (for Windows)\n\nDo this in ProxSpace:\n\n```bash\ncd ~/proxmark3/tools/kgh\nrm -rf build-lite\ncmake -G \"MSYS Makefiles\" -S . -B build-lite \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-lite --target legic_kgh_tool -j\nobjdump -p build-lite/legic_kgh_tool.exe | grep -i \"DLL Name\"\n```\n\n## Building Linux\n\n```bash\ncd tools/kgh\nrm -rf build-linux\ncmake -S . -B build-linux \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-linux --target legic_kgh_tool -j\nldd build-linux/legic_kgh_tool\n```\n\n## Static Link Notes\n\n- `legic_kgh_tool` is linked against `pm3rrg_rdv4_static`.\n- On MinGW, CMake adds `-static -static-libgcc` for the target.\n- Linux builds are not the same as the ProxSpace single-EXE deployment.\n- If CMakeCache paths change between ProxSpace and a native shell, delete the build dir and reconfigure.\n","isInternal":false,"tokens":661,"sizeBytes":2117}],"systemPromptSnippet":"<yakaai_skills repo=\"RfidResearchGroup/proxmark3\">\n<!-- File: AGENTS.md (Tokens: ~2136 | Category: root-instruction) -->\n# AGENTS.md\n\nInstructions for AI coding agents (and humans using one) proposing pull requests\nto this repository. This complements `README.md` and `Maintainers.md`; when in\ndoubt, those human-facing docs win.\n\n## Repo shape (quick map)\n\n- `bootrom/`, `armsrc/` — ARM firmware for the device (Proxmark3\n  hardware targets), buildable via **either** the top-level\n  `Makefile` **or** their respective `CMakeLists.txt`. Keep both build definitions in sync.\n- `client/` — host-side client, buildable via **either** the top-level\n  `Makefile` **or** `client/CMakeLists.txt`. Keep both build definitions in sync.\n- `client/experimental_lib/` — experimental shared-lib build of the client,\n  has its own `CMakeLists.txt`. Any change to the client `client/CMakeLists.txt` almost always implies a change in `client/experimental_lib/CMakeLists.txt`.\n- `common_arm/`, `common/` — shared code between firmware and/or client.\n- `tools/` — standalone tool suites (`hitag2crack`, `mfc/*`, `fpga_compress`,\n  `ePassport`, etc.), each with its own `Makefile` and its own `check` target.\n\n## Before opening a PR: build matrix\n\nDo not treat \"it compiles for me\" as done. For any non-trivial change, verify\nacross the axes below (skip only the ones genuinely unaffected by your diff,\nand say explicitly in the PR description which axes you *did* and *did not*\ntest):\n\n1. **Zero warnings.** `make clean && make all` must complete with no compiler\n   warnings on the default toolchain (gcc). Warnings are effectively treated\n   as errors in this project's normal dev flow.\n2. **Second compiler.** Also try building host client and host tools (if touched) with clang, e.g. `make clean && make client -j CC=clang CXX=clang++ LD=clang++`\n   and fix anything it flags that gcc didn't — clang's\n   diagnostics catch different classes of bugs (e.g. some format-string and\n   sign issues).\n3. **Both client build systems.** If you touched client code, dependencies,\n   or build flags, update and test:\n   - `client/Makefile` (default `make client`)\n   - `client/CMakeLists.txt`\n   - `client/experimental_lib/CMakeLists.txt`\n   A file added to one and not the others is an incomplete PR.\n4. **ARM firmware targets.** If you touched `armsrc/`, `bootrom/`,\n   `common_arm/`, or anything reachable from firmware, compile at least for **both**\n   main platform configs (`PLATFORM=` per `Makefile.platform`): PM3RDV4 and PM5.\n   Use also PLATFORM_EXTRAS if relevant to your changes.\n5. **Cross-OS for platform-sensitive code.** Anything touching serial/USB\n   comms, filesystem paths, threading, or conditional `#ifdef _WIN32` /\n   `__APPLE__` / `__linux__` code needs to at least be reasoned through, and\n   ideally exercised, on all three supported environments: native Linux,\n   Windows (ProxSpace or WSL, per the project's documented Windows build\n   path), and macOS. Say in the PR which of these you actually ran.\n6. **Offline tests.** Run `make check` (or the narrower `<target>/check`,\n   e.g. `client/check`, `armsrc/check`) and make sure it stays green. Add to\n   `tools/pm3_tests.sh` coverage if you're adding a new command/module that\n   can be exercised offline.\n\n### Never `rm -rf` an `obj/` directory\n\nThe ARM-side build has no `mkdir` for its object directories — only the host\nbuild creates its own. `armsrc/obj/`, `armsrc/obj/Standalone/` and\n`bootrom/obj/` exist because each is held open in git by a tracked `.dummy`\nfile, and `make clean` deliberately deletes only the files *inside* them.\nDelete such a directory and nothing recreates it. Every subsequent build dies\nwith messages that give no hint a tracked file went missing:\n\n```\nError. Cannot open output file obj/fpga_all.bit.z\nFatal error: can't create obj/start.o: No such file or directory\n```\n\n`git checkout -- armsrc/obj/.dummy armsrc/obj/Standalone/.dummy bootrom/obj/.dummy`\nputs it back. `git status` showing a deleted `.dummy` is the tell.\n\nIf you script a build matrix, switch `PLATFORM=` / `STANDALONE=` and let make\ndecide what to rebuild — changing those changes the defines, which is enough to\nforce the recompile you want.\n\n## Code style\n\n- Respect the style used in this project: trailing\n  whitespace/EOL cleanup, Equivalent of `astyle` on `*.c`/`*.h` with \n  `--style=google --indent=spaces=4 --indent-switches --keep-one-line-blocks\n  --max-continuation-indent=60 --pad-oper --unpad-paren --pad-header\n  --align-pointer=name` and on `*.cpp`/`*.hpp` (same, minus `--pad-oper`).\n  Don't hand-format C/C++ differently from what `astyle` produces.\n- Don't reformat existing code outside of your changes, only format your own code.\n- If your change adds/changes a client command, run `make commands` to\n  regenerate `doc/commands.md` and `doc/commands.json` — don't hand-edit\n  those generated files.\n- **Keep comments short and direct.** This codebase comments in brief fragments,\n  usually one line. Match the surrounding file. No walls of text. A comment earns\n  its place by saying something the code cannot e.g. a return contract, where a\n  magic number came from, or why something is deliberately absent. Do not restate\n  the code or place commit message content, reasoning, or justification into the\n  source. Anything longer than 3-4 lines usually belongs in the PR instead.\n- **Preserve existing comments** in code you touch or move. Don't drop,\n  \"clean up\", or silently reword neighboring comments as a side effect of an\n  unrelated change.\n- Keep the GPLv3 file header banner (see any existing `.c`/`.h`/`Makefile`)\n  on new files; copy it verbatim from a neighboring file of the same type.\n\n## PR description format\n\nStructure the PR description in these sections:\n\n- **Problem** — what's actually wrong today, with concrete symptoms/examples,\n  not just \"code is messy.\"\n- **Change** — what you did, file by file if it helps a reviewer, and *why*\n  this approach (e.g. why runtime computation instead of a regenerated table).\n- **Behaviour change** — call out explicitly, as its own section, anything a\n  user or downstream code could observe differently after your change, even\n  if the new behavior is strictly more correct. Don't let this hide inside\n  the diff.\n- **Testing** — be specific and be honest:\n  - List the exact build variants exercised, e.g. \"readline (`make`),\n    linenoise (`SKIPREADLINE=1`), CMake client, `experimental_lib` (LIBPM3),\n    `PLATFORM=PM5` and default RDV4.\"\n  - Explicitly state what you did **not** test (e.g. \"Not tested here:\n    Windows/ProxSpace and macOS\") rather than implying full coverage. Where\n    possible, give a one-line reason the untested paths are low-risk (e.g.\n    \"only uses `scandir`/`alphasort`, already used portably elsewhere in\n    `fileutils.c`\").\n  - Net diff size and notable deletions are worth mentioning — removing a\n    stale generated table or dead code is a feature of the PR, not a\n    side note.\n\n## PR checklist (put this in the PR description)\n\n- [ ] Proper style of own code, no unrelated reformatting included\n- [ ] Builds warning-free with gcc; also tried with clang\n- [ ] `client/Makefile`, `client/CMakeLists.txt`, and\n      `client/experimental_lib/CMakeLists.txt` all updated if client sources\n      changed\n- [ ] ARM firmware builds clean for RDV4 and PM5 platform configs (if\n      `armsrc`/`bootrom`/`common_arm` touched)\n- [ ] Platform-sensitive code reasoned about / tested on Linux, Windows\n      (ProxSpace/WSL), and macOS (if applicable) — state which were tested\n- [ ] Existing comments in touched files preserved\n- [ ] New comments short and direct, no restated code or PR prose\n- [ ] `doc/commands.md` / `doc/commands.json` regenerated if commands changed\n\n## Commit attribution\n\nIf an AI agent authored or materially contributed to a commit, say so with a\ntrailer, the same way you'd credit a human co-author, e.g.:\n\n```\nCo-Authored-By: <agent/model name> <noreply@anthropic.com>\n```\n\nDon't omit this to make a PR look purely human-written.\n\n## What not to do\n\n- Don't add `-Werror`-suppressing flags or `#pragma` warning silences to make\n  a warning disappear — fix the underlying issue.\n- Don't introduce a dependency in one client build file without mirroring it\n  in the other two.\n- Don't submit ARM-side changes only test-built for one platform target.\n- Don't `rm -rf` any `obj/` directory to force a rebuild — it deletes tracked\n  `.dummy` files and breaks the build until they are restored. Use `make clean`.\n\n<!-- File: tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md (Tokens: ~300 | Category: anthropic-skill) -->\n# OpenCL-Headers Skill\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/CODE_OF_CONDUCT.md)\n\n<!-- File: tools/mfc/card_reader/mf_nonce_brute_examples.md (Tokens: ~2826 | Category: anthropic-skill) -->\nmf_nonce_brute\n==============\n\nNested autenticated sector key recovery tool\n-----------------------------------------------\n\nCompatible tags:\n* Mifare Classic 1k (4k)\n* Mifare Plus in SL1 mode\n\nTo recover keys to nested autenticated sectors you need a reader-card communication log. To get it use \nhardware tools that able to sniff communication (for example Proxmark3 or HydraNFC).\n\nThis enhanced version:  \nFirst 2 bytes should be bruteforced in phase 2 with mf_key_brute tool that interacts with a card.\n\nSample trace:\n```\n    93 70 fd ac f6 d8 7f 21 4f                            // select card with UID fdacf6d8\nTAG 08 b6 dd                                              // sak\n    60 04 d1 3d                                           // wanna auth block 0x04 with A key\nTAG ed 12 9c 74                                           // 1st auth clear text nt\n    55 53 9f cc 41 8d e8 f3                               // {nr}, {ar}  (nr^ks1, ar^ks2 )\nTAG 05 49 e1 65                                           // {at} ( at^ks3 )\n    03 24 26 56                                           // wanna read block 0x04\nTAG ac 69 ef 58 45 e1 c2 1d a9 47 a5 94 54 ef 5d c7 1e a9 // block 0x04 content\n    d4 3e a8 aa \nTAG 8e 8e e3 e6 e9 e2 5f dd f6 08 ce fb 02 6a db 75 94 2f \n    79 77 68 3c \nTAG e0 00 00 80 80 08 cc 80 08 9c 82 e0 68 64 60 30 91 60  // 18 bytes = 16 byte content + 2 bytes crc\n    ea 88 c3 c2                                            // 4 byte read cmd\nTAG a3 76 dc df c1 42 e0 ee c6 75 a4 ca eb 0c da eb 46 a0  // 18 bytes = 16 byte content + 2 bytes crc ks8 + crc\n    2d 27 ab 6f                                            // wanna auth to 0x04 block with key B\n\n-------Until this line we can recover key or decrypt communication with no troubles (see mfkey64 tool)--------------------------------\n\nTAG 52 6e af 8b                                            // nested auth encrypted tag nonce that we don't know\n    8e 21 3a 29 a4 80 7e 02                                // {nr} = nr^ks1, {ar} = ar^ks2\nTAG b9 43 74 8d                                            // {at} = at^ks3\n    e2 25 f8 32                                            // probably next command (actually is read block cmd, but we don't know it yet)\nTAG 1f 26 82 8d 12 21 dd 42 c2 84 3e d0 26 7f 6b 2a 81 a9  // probably data\n    ba 85 1d 36                                            // probably read cmd\nTAG 62 a8 78 69 ee 36 22 16 1c ff 4b 4e 69 cb 27 c2 e8 7e  // probably data\n    a7 b1 c8 da                                            // probably read cmd\nTAG b2 fc 6c 65 60 ec 35 83 87 56 e3 7e 3c bf 38 b8 73 21  // probably data\n    99 92 13 55                                            // probably read cmd\nTAG 93 5b 65 a3 1d 8c 75 b8 3a 63 e2 31 f0 d0 a9 24 9a f6  // probably data\n```\n\n\nPhase 1\n-------\n\nSyntax:  \n`mf_nonce_brute <uid> <{nt}> <nt_par_err> <{nr}> <{ar}> <ar_par_err> <{at}> <at_par_err> [<{next_command}>]`\n\nExample: if `{nt}` in trace is `8c!  42 e6! 4e!`, then `{nt}` is `8c42e64e` and `nt_par_err` is `1011`\n\nExample with parity (from this trace http://www.proxmark.org/forum/viewtopic.php?pid=550#p550) :\n\n```\n + 561882:  1 :     26\n +     64:  2 : TAG 04  00\n +  10217:  2 :     93  20\n +     64:  5 : TAG 9c  59  9b  32  6c                        UID\n +  12313:  9 :     93  70  9c  59  9b  32  6c  6b  30\n +     64:  3 : TAG 08  b6  dd\n + 923318:  4 :     60  00  f5  7b                            AUTH Block 0\n +    112:  4 : TAG 82  a4  16  6c                            Nonce Tag (nt)\n +   6985:  8 :     a1  e4! 58  ce! 6e  ea! 41  e0!           {nr}, {ar}\n +     64:  4 : TAG 5c! ad  f4  39!                           {at}\n + 811513:  4 :     8e  0e! 5d! b9                            AUTH Block 0 (nested)\n +    112:  4 : TAG 5a! 92  0d! 85!                           Nonce Tag ({nt})\n +   6946:  8 :     98! d7  6b! 77  d6  c6  e8  70            {nr}, {ar}\n +     64:  4 : TAG ca  7e! 0b! 63!                           {at}\n + 670868:  4 :     3e! 70  9c! 8a\n +    112:  4 : TAG 36! 41  24! 79\n +   9505:  8 :     1b! 8c  3a! 48! 83  5a  4a! 27\n +     64:  4 : TAG 40! 6a! 99! 4b\n + 905612:  4 :     c9  7c  64! 13!                           !crc\n +    112:  4 : TAG b5! ab! 1d! 2b\n +   6936:  8 :     7e! d2  5c! ca! 4b! 50! 88! c4            !crc\n +     64:  4 : TAG bf  dd  01  be!\n + 987853:  4 :     56  98  49  d6!                           !crc\n```\n=> Using the plaintext tagnonce `nt`=`82a4166c`\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001 8e0e5db9  \n                 |        |        |     |        |        |    |        |    |\n                 +UID     +nt      |     +{nr}    +{ar}    |    +{at}    |    +{next cmd}\n                                   + nt is clear           +ar_par_err   +at_par_err\n```\n\nWithout a next command, it still finds a possible key candidate.\n```\n./mf_nonce_brute 9c599b32 82a4166c clear a1e458ce 6eea41e0 0101 5cadf439 1001\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85`, it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111\n```\n\nThis one uses the encrypted tagnonce `{nt}`=`5a920d85` and the encrypted cmd `3e709c8a` to validate , it finds a valid key.\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\n```\nFull output:\n```\n./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a\nMifare classic nested auth key recovery. Phase 1.\n-------------------------------------------------\nuid:            9c599b32\nnt encrypted:   5a920d85\nnt parity err:  1011\nnr encrypted:   98d76b77\nar encrypted:   d6c6e870\nar parity err:  0000\nat encrypted:   ca7e0b63\nat parity err:  0111\nnext cmd enc:   3e709c8a\n\n\nStarting 4 threads to bruteforce encrypted tag nonce last bytes\nCMD enc(3e709c8a)\n    dec(6000f57b)       <-- Valid cmd\n\nValid Key found: [ffffffffffff]\n\nTime in mf_nonce_brute (Phase 1): 1763 ticks 2.0 seconds\n```\n\n[2024-07-11]\nThere is an odd case where we find multiple valid MIFARE Classic protocol commands with a valid ISO14443-A CRC when decrypting four bytes and are bruteforcing the last upper 16 bit of keyspace in phase 3. \n\nThe command has been updated to give a more informative text in order to help the user understanding and what to do next.\n\n```\n./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n```\n\n\nWhen running you get the following full output\n\n```\n./mf_nonce_brute$ ./mf_nonce_brute fcf77b54 1b456bdd 1110 f215b6 f9eb95e9 0011 bf55d0b1 0000 AAD4126B\n\nMifare classic nested auth key recovery\n\n----------- information ------------------------\nuid.................. fcf77b54\nnt encrypted......... 1b456bdd\nnt parity err........ 1110\nnr encrypted......... 00f215b6\nar encrypted......... f9eb95e9\nar parity err........ 0011\nat encrypted......... bf55d0b1\nat parity err........ 0000\nnext encrypted cmd... AAD4126B\n\nBruteforce using 8 threads\n\n----------- Phase 1 pre-processing ------------------------\nTesting default keys using NESTED authentication...\n\n----------- Phase 2 examine -------------------------------\nLooking for the last bytes of the encrypted tagnonce\n\nTarget old MFC...\nCMD enc( aad4126b )\n    dec( 302424cf )    <-- valid cmd\n\nKey candidate [ ....37afcc2b ]\nKey candidate [ a70d37afcc2b ]\n\nexecution time 0.47 sec\n\n----------- Phase 3 validating ----------------------------\nuid.................. fcf77b54\npartial key.......... 37afcc2b\npossible key......... a70d37afcc2b\nnt enc............... 1b456bdd\nnr enc............... 00f215b6\nnext encrypted cmd... AAD4126B\n\nLooking for the upper 16 bits of the key\n\nenc:  AAD4126B\ndec:  610BFEDC\n\nValid Key found [ 7c2337afcc2b ]\n\n\nenc:  AAD4126B\ndec:  302424CF\n\nValid Key found [ a70d37afcc2b ] - matches candidate\n\n\nOdd case but we found 2 possible keys\nYou need to test all of them manually, start with the one matching the candidate\n\n```\n\n<!-- File: tools/mfc/card_reader/mfkey_examples.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Card_reader Skill\n\nPath: `tools/mfc/card_reader/mfkey_examples.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/mfc/card_reader/mfkey_examples.md)\n\n<!-- File: tools/deprecated-hid-flasher/flasher/README.md (Tokens: ~88 | Category: plugin-manifest) -->\nCompilation notes\n=================\n\nBesides the global Proxmark3 requirements, this flasher compatible with very old firmwares requires the libusb 0.1 to work.\nSo you'll need to install the libusb 0.1 package first.\n\n* OSX: libusb-compat\n* Debian-alike: libusb-0.1-4 libusb-dev\n* Arch: libusb\n* Fedora: libusb-devel\n\n<!-- File: tools/ePassport/README.md (Tokens: ~4872 | Category: plugin-manifest) -->\n# ePassport\n\nAn ePassport (eMRTD) viewer: reads a passport chip through the Proxmark3 and\nrenders it as a passport data page.\n\nEverything runs **offline**. No telemetry, no cloud OCR, no network calls of\nany kind — every font and asset is bundled.\n\n```\n./ePassport.py                                   # normal use\n./ePassport.py --dump DIR                       # open a saved dump, no hardware\n./ePassport.py --dry-run pm3.log --dump DIR     # replay a session you recorded\n./ePassport.py --help\n```\n\n`ePassport.py` is a plain launcher script — run it directly (it has a shebang) or with `python3`, from anywhere, by path or\nfrom a symlink; there is nothing to install and no `PYTHONPATH` to set. If a\ndependency is missing it says which one, which interpreter it used, and the\nexact command to fix it.\n\nIt needs an interpreter that has the requirements. With a virtualenv, either\nactivate it first or point at it directly:\n\n```bash\n/path/to/venv/bin/python ./ePassport.py\n```\n\n---\n\n## Install\n\n```bash\npython3 -m pip install -r requirements.txt\n```\n\nKivy is required. Everything else is optional and the app degrades with a\nmessage telling you what to install:\n\n| Missing | What stops working |\n|---|---|\n| `opencv-python-headless` | the Scan screen (camera) |\n| `pytesseract` + the `tesseract-ocr` binary | MRZ OCR — manual entry still works |\n| `Pillow` / `glymur` | portrait decoding (DG2 is usually JPEG2000) |\n| `asn1crypto` / `cryptography` | EF_SOD inspection and the DG hash table |\n\nFor the best OCR accuracy install the OCR-B or `mrz` traineddata; the app picks\nit up automatically and falls back to `eng` with a character whitelist.\n\n`sudo apt install xclip` enables Kivy's cut-buffer support. The app filters\nthe noisy `[CRITICAL] [Cutbuffer]` complaint either way; nothing depends on it.\n\n## Relationship to proxmark3\n\nThis app **does not modify the proxmark3 tree**. The only coupling is the `pm3`\nCLI, invoked in one-shot command mode:\n\n```\npm3 -c \"hf emrtd dump -n <DOCNUM> -d <YYMMDD> -e <YYMMDD> --dir <outdir>\"\npm3 -c \"hf emrtd info --dir <existing dump>\"     # offline mode\n```\n\nThe binary is located via `$PM3_BIN` → the configured path → `PATH` → `~/pm3/pm3`\n→ the `./pm3` wrapper of an enclosing proxmark3 source tree.\n\nThe country-name table in `emrtd/countries.py` is **generated** from the\nproxmark3 client's own ISO-3166 table (`fdxbCountryMapping` in\n`client/src/cmdlffdxb.c`). Regenerate it with:\n\n```bash\npython3 tools_gen_countries.py ../../client/src/cmdlffdxb.c\n```\n\n### Authentication\n\n| You have | Enter | What runs |\n|---|---|---|\n| The MRZ | document number + both dates, or line 2 | PACE with the MRZ, falling back to BAC |\n| The CAN | the number printed on the data page | `--can` (PACE only) |\n\nThe **CAN** is the short number printed on the data page — usually 6 digits.\nIt is a PACE password, so it is mutually exclusive with the MRZ, and BAC can\nnever use it. The Authentication dropdown forces `--pace` or `--bac` when you\nwant to test one path; leave it on Automatic otherwise.\n\nWrong CANs are counted by the chip and the password will eventually block, so\nthat failure is called out separately from a wrong MRZ.\n\n### Two things worth knowing about `hf emrtd`\n\n- **All three of `-n/-d/-e` must be supplied**, or the client silently drops to\n  no-BAC mode and fails on any protected passport. The app refuses a partial\n  triple rather than passing it on.\n- **The `pm3` wrapper blocks forever** waiting for a device when none is\n  attached. The app watches for that line and reports \"No Proxmark3 found\"\n  immediately instead of sitting on the timeout.\n\n## Using it\n\n1. **Scan** the MRZ with a camera, or **type** the three values. A full 44-char\n   MRZ line 2 takes precedence and is passed as `-m`, which avoids\n   field-splitting mistakes.\n2. **Read** — pm3 runs on a worker thread and streams into the LOG tab, with a\n   determinate progress bar and a Cancel that actually kills the process.\n3. The dump is parsed from the **binaries** (BER-TLV), never scraped from\n   `hf emrtd info` stdout, and rendered as a data page.\n\nTabs across the top: `DATA PAGE` · `PERSONAL` (DG11) · `ISSUER` (DG12) ·\n`SECURITY` (SOD/DG14/DG15) · `FILES` · `LOG`.\n\n### Output\n\nThe app is quiet by default. Kivy 2.3 takes its log level from\n`~/.kivy/config.ini`, which is shared with every other Kivy app on the machine,\nso rather than rewrite that the app drops Kivy's console handler and installs\nits own for warnings and above. pytesseract (which logs a full tesseract\ncommand line per frame), OpenCV and its V4L2 backend are quietened the same\nway. `-v` puts all of it back.\n\n### Resizing\n\nThe page is laid out **once** at a fixed resolution and then drawn scaled, so a\nresize costs a matrix multiply rather than a full re-flow. Re-flowing it on\nevery resize event re-rendered every label and regenerated the security print\nseveral times a frame, which made dragging a window edge crawl and the contents\njitter as text reflowed under the cursor.\n\nMeasured over twenty resize steps:\n\n| | Before | After |\n|---|---|---|\n| Page widget redraws per step | 21 | 0 |\n| Label re-renders per step | 65 | 11 (window chrome only) |\n| Time in text rendering | 182 ms | 10 ms |\n\nTwo supporting fixes: redraws are coalesced onto a `Clock` trigger so `pos` and\n`size` changing separately cannot cause three redraws in one frame, and MRZ\nglyphs are cached per (character, size) — an MRZ is ~90 characters drawn from\nan alphabet of 37, so it was building ninety textures to show at most\nthirty-seven distinct ones.\n\n### Why a document may not fill the window\n\nBoth formats are always scaled as large as they fit without distorting, so\nneither is ever \"shrunk\" — but a document and a window are different shapes,\nand only one of the two dimensions can fill. Whichever document is closer to\nthe window's shape uses more of it:\n\n| Window content shape | Passport (1.42) | Card (1.59) |\n|---|---|---|\n| 1.61 (wide) | 88% wide, 100% tall | 99% wide, 100% tall |\n| 1.42 (the default) | **100% wide, 100% tall** | 100% wide, 90% tall |\n| 2.59 (very wide) | 55% wide, 100% tall | 61% wide, 100% tall |\n\nThe default window is sized so its **content area comes out at the reference\ndocument's own 125:88**, so a passport fills it exactly on first run. Stretch\nthe window wide and both documents will letterbox at the sides; that is the\nshape mismatch, not the app giving up on the space.\n\n### Small windows\n\nThe minimum window is 760x520 and the app remembers the size you leave it at.\nEverything is built to survive that:\n\n- the passport page scales as a unit and keeps its aspect;\n- the tab strip shares its width rather than claiming fixed slots;\n- the FILES table uses proportional columns, so the state column does not fall\n  off the edge;\n- the hex viewer fits **16, 8 or 4 bytes per row** to whatever width the pane\n  has, because a hex dump must not wrap.\n\n### Speed\n\nAn MRZ scan settles in roughly a second. What that took:\n\n| Change | Effect |\n|---|---|\n| Cheap pre-gate before OCR (`looks_like_text`) | a badly framed strip costs ~0.3 ms instead of ~400 ms |\n| Skip frames already processed | no repeat OCR of an identical frame |\n| Pace the loop instead of adding to it | the interval no longer stacks on top of the work |\n| Cache the language lookup | it shelled out to tesseract every frame |\n| Stop escalating variants with no signal | 2 passes instead of 3 on hopeless frames |\n| Remember the last winning variant | dim lighting costs 1 pass, not 3 |\n\nMeasured on a live camera: mean OCR pass 381 ms → 163 ms, time to acceptance\n3.1 s → 1.3 s, with accuracy unchanged on the synthetic bench.\n\nThe gate runs *after* deskew — it measures horizontal bands of ink, and tilted\ntext smears those bands together.\n\nAn in-process binding (`tesserocr`) is ~3× faster per call than re-launching\nthe tesseract binary, and was tried. It is **not** used: the PyPI wheel bundles\nits own leptonica, and pairing that with a system `tessdata` directory hung\nindefinitely mid-recognition. A backend that can wedge the OCR thread is worse\nthan a slower one.\n\n### Cameras\n\nThe Scan screen enumerates capture devices by name from\n`/sys/class/video4linux` — without opening them, because opening a device is\ndisruptive if something else is using it.\n\n- **No camera**: the screen says so and offers **Rescan for devices**. Manual\n  entry is always available and works just as well.\n- **One or more**: a dropdown lists them by name (`0: IPEVO Ziggi-HD Plus`).\n  The choice is remembered.\n\nLinux commonly exposes several `/dev/videoN` nodes for one physical camera,\nonly one of which delivers frames — `isOpened()` returns true for the others.\nThe app therefore treats a successful *read* as the test, and falls back to a\nneighbouring index automatically. **Rescan** probes every device to label the\ndead ones `(no frames)`; it stops the preview first so the probe and the\ncapture thread do not fight over the device.\n\nOnly line 2 is needed for BAC, so the scan accepts a lone line 2 when its five\ncheck digits — composite included — all pass.\n\n### What a \"valid\" MRZ scan does and does not prove\n\nA scan is accepted only when every check digit validates **and** two\nconsecutive frames agree. That still does not prove the document number is\nright. The 7-3-1 checksum is taken modulo 10 and its weights are coprime with\n10, so swapping a character for one whose value differs by a multiple of 10\nleaves every check digit — composite included — unchanged. The blind pairs are\n`L`/`1`, `S`/`8`, `G`/`6`, `Z`/`5`, `I`/`8`, `D`/`3` … which are exactly the\nswaps OCR is most likely to make.\n\nThat is why a scan **fills the entry form and stops** rather than starting a\nread, and why the form flags the document number for a second look. If BAC\nthen fails, the document number is the first thing to check.\n\n(Confusions that are *not* blind, such as `O` read as `0` in a country code,\nare repaired automatically by position before validation.)\n\n### Drawing the page\n\nA TD1 is an ID-1 card (85.6 x 54 mm), not a small passport data page\n(125 x 88 mm), and its three-line MRZ takes about a quarter of its height\nagainst an eighth for a passport's two lines. The page is drawn at whichever\nshape the document really is.\n\n**Two scale modes**, because you cannot have both at once. OCR-B is a fixed\n2.54 mm pitch on every format, but a character is 2.97% of a card's width and\nonly 2.03% of a passport's — so a card's MRZ is inherently half again as large\nrelative to its own document:\n\n| Mode | What it gives you | What it costs |\n|---|---|---|\n| **Fit window** (default) | every document fills the window | a card's MRZ prints ~1.5x a passport's on screen |\n| **True size** | MRZ print identical across formats, as in the hand | a card is drawn two thirds the width, leaving margins |\n\nOpening a dump re-fits the page for whatever format it turns out to be, so the\nbutton is a preference you set once, not something to press after every load.\nThe toolbar button swaps them and the choice is remembered. It is labelled\nwith the **action**, like the chrome button beside it: reading \"Fit window\"\nmeans clicking will fit the window, so you are currently at true size. A\npassport looks identical either way; only formats smaller than the reference\npage differ.\n\nWithin the band, the MRZ block is sized to fit in **both** directions — the\nsmaller of the width- and height-derived sizes wins, and a block that does not\nfill the width is centred. Fitting the width alone pushed a card's MRZ out over\nthe fields above it; leaving a full line of air between rows then shrank it\nuntil it no longer reached the margins.\n\nThe **portrait** is sized from the page width and the real 35 x 45 photo shape,\ncapped against the space above the band — a fraction of page height alone made\nit swallow a short card. The frame keeps the photo aspect whichever constraint\nbinds, so an image never sits letterboxed in white bars.\n\nThe guilloche is generated procedurally (superimposed hypotrochoids at low\nalpha) — nothing is traced from a real document's security print. It is clipped\nto the printed frame **geometrically**, with a Liang-Barsky segment clip, not\nwith a stencil: this widget can sit inside another `StencilView`, and Kivy's\nnested stencils do not intersect, so an inner stencil silently stops clipping\nanything. That bug had the pattern spilling past the page edge onto the\nwindow background.\n\nText over the pattern measures about 15:1 contrast, well clear of the 4.5:1\nfloor.\n\n### Fields that may not be there\n\nDG11 and DG12 are optional and plenty of real passports omit them entirely —\nplace of birth, date of issue and issuing authority are printed on the page but\nnever written to the chip. Those fields say **\"not on chip\"** rather than\nshowing an empty value, so a missing data group is not mistaken for a parse\nfailure.\n\nThe **personal number** is recovered from the MRZ optional-data field when\nDG11 is absent — several states, Sweden among them, put the national identity\nnumber there. The field's caption says `PERSONAL No. (FROM MRZ)` when it came\nfrom that fallback.\n\n### What the SECURITY tab does and does not check\n\nIt hashes each dumped data group and compares against the hash table inside\nEF_SOD, marking every DG **match / MISMATCH / not checked**. It does **not**\nvalidate the signer certificate chain — that needs the issuing country's CSCA\ncertificate, which the app deliberately does not fetch.\n\n## Where your reads go\n\nEvery read writes to:\n\n```\n~/.local/share/ePassport/dumps/<UTC-timestamp>/\n```\n\ncreated `0700`. The app was previously called `pm3-passport`; if a directory\nof that name exists it is moved to the new one on first run, so earlier reads\nare carried across rather than orphaned. You do not need to remember that: **Dumps…** in the toolbar\nlists every read with its timestamp and contents. From there you can open one,\ndelete one with the bin button, open the folder in your file manager, or clear\nout the empty directories left behind by reads that failed. The path is also in\nthe status bar (click it) and in the log at the start of every read.\n\nEvery read also leaves `pm3.log` in its directory: the client output for that\nrun, which is the only record of why a read that dumped nothing gave up. It\nholds what the LOG pane showed and not the MRZ or CAN you typed, and it does\nnot count as a file when the app decides whether a read produced anything.\n\nDeleting always asks first, and says what it is about to destroy — a dump holds\na real portrait and a real MRZ.\n\n**Opening a dump from elsewhere** (a colleague's, or the generated samples):\n**Dumps… → Samples…** goes straight to `./samples`, and **Browse…** opens a\npicker with one-click jumps to **Recent**, **Dumps**, **Samples**, **Working\ndir** and **Home**, plus a path box you can type or paste into.\n\nThe picker reopens **beside the last dump you loaded**, so picking a second\ndump next to the first does not mean navigating there again. Shortcuts that do\nnot exist are not shown — `Samples` only appears once you have generated them —\nand duplicates collapse, so `Recent` and `Samples` do not both appear when they\nare the same folder.\n\n## Your data\n\n- Dumps are `0700` and there is a **Delete dump** button.\n- MRZ values and document numbers are never written outside that directory.\n- \"Remember\" on the entry screen defaults to **off** — those values are live\n  credential material.\n- The app is strictly read-only: it displays what the chip returns, and no\n  field is editable.\n\n## Development\n\n```bash\nmake test              # 297 tests, no hardware needed\nmake samples           # generate the fabricated dumps into ./samples\nmake clean             # drop __pycache__ and the test cache\nmake distclean         # the above, plus the generated samples\nmake format            # reformat with black\nmake help              # the rest\n```\n\nThe proxmark3 root `Makefile` recurses in here too, following the same pattern\nit uses for `hitag2crack`:\n\n```bash\nmake ePassport/clean     # from the repository root\nmake ePassport/test\nmake ePassport/help\n```\n\nePassport is deliberately **not** in the root `TARGETS`, so a plain `make` or\n`make clean` at the top level does not touch it — it builds nothing and is not\npart of the firmware or client build.\n\n`make` shells out to `python3`; if your dependencies live in a virtualenv,\npoint it at that interpreter:\n\n```bash\nmake test PYTHON=/path/to/venv/bin/python\n```\n\nThe same without `make`:\n\n```bash\npython3 -m pytest tests/ -q\npython3 tools_make_sample.py [DIR]              # generate the sample dumps\npython3 -m epassport.emrtd samples/td3_utopia   # headless: parse and print\npython3 -m black epassport tests tools_*.py\n```\n\n### Nothing derived from a document is checked in\n\nThis tree carries **no dumps, no logs and no images**. A dump holds a live\nportrait and MRZ, and a screenshot of one is just as identifying — so none of\nit belongs in version control, not even the fabricated kind, and `.gitignore`\nrefuses the file types outright.\n\nWhat you need instead is generated:\n\n```bash\npython3 tools_make_sample.py [DIR]      # fabricated dumps, default ./samples\n```\n\nThey are documents of the fictional ICAO specimen state \"Utopia\": no real\npersonal data, no real security print. `td3_utopia` carries a genuinely signed\nEF_SOD, `td3_utopia_tampered` is the same document with DG2 swapped after\nsigning so the SECURITY tab has a MISMATCH to show, and `td1_utopia_idcard` is\na TD1 card with no DG11/DG12 or SOD.\n\nThe tests never touch that directory: `tests/conftest.py` builds its own copy\ninto a temporary directory, and the recorded pm3 sessions used by the\n`--dry-run` tests are inline in `tests/test_pm3_client.py`.\n\nTo replay a real session, record it yourself:\n\n```bash\npm3 -c \"hf emrtd dump -n ... -d ... -e ...\" | tee pm3.log\n```\n\n### Layout\n\n```\nMakefile             run / test / format / clean\nePassport.py         the launcher; everything below is the implementation\nepassport/\n  app.py               app, screens, worker threads\n  __main__.py          shim so `python3 -m epassport` still works\n  config.py            paths, settings, 0700 data dir\n  pm3/client.py        subprocess, streaming, cancel, timeout\n  pm3/errors.py        typed failures + plain-English remedies\n  emrtd/tlv.py         BER-TLV reader\n  emrtd/mrz.py         TD1/TD2/TD3, check digits, date window\n  emrtd/dg.py          per-DG decoders -> PassportRecord\n  emrtd/sod.py         optional CMS/SOD inspection\n  emrtd/images.py      JPEG/JP2 carving out of CBEFF blobs\n  emrtd/model.py       PassportRecord: the single UI-facing object\n  ocr/                 camera thread, OCR pipeline, accept rule\n  ui/                  Kivy widgets and .kv files\n```\n\n**Threading contract:** the pm3 subprocess, file parsing, image decoding and\nOCR all run off the main thread; UI mutation happens only via\n`Clock.schedule_once`. The app never freezes while a dump runs.\n\n**Single source of truth:** every parser produces one `PassportRecord`, and the\nUI binds only to that — which is why \"open saved dump\" and \"read from card\" are\nthe same rendering path.\n\n<!-- File: tools/hitag2crack/common/OpenCL-Headers/README.md (Tokens: ~300 | Category: plugin-manifest) -->\n# OpenCL-Headers Documentation\n\nPath: `tools/hitag2crack/common/OpenCL-Headers/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/RfidResearchGroup/proxmark3/HEAD/tools/hitag2crack/common/OpenCL-Headers/README.md)\n\n<!-- File: tools/hitag2crack/crack2/README.md (Tokens: ~543 | Category: plugin-manifest) -->\nht2crack2 suite\n\n\n\nBuild\n-----\n\nEdit ht2crack2buildtable.c and set the DATAMAX, NUM_BUILD_THREADS and NUM_SORT_THREADS values.\nThese are important if you want it to run quickly.  Ideally set DATAMAX to the largest value\nthat you can get away with and set NUM_BUILD_THREADS and NUM_SORT_THREADS to the number of\nvirtual cores you have available, which MUST be a power of 2.  NUM_BUILD_THREADS MUST be >=\nNUM_SORT_THREADS.\n\nCalculate DATAMAX = free RAM available / 65536, and then round down to a power of 10.\n\nThe Makefile is configured for linux.  To compile on Mac, edit it and swap the LIBS= lines.\n\n```\nmake clean\nmake\n```\n\nRun ht2crack2buildtable\n-----------------------\n\nMake sure you are in a directory on a disk with at least 1.5TB of space.\n\n```\n./ht2crack2buildtable\n```\n\nWait a very long time.  Maybe a few days.\n\nThis will create a directory tree called table/ while it is working that will contain\nfiles that will slowly build up in size to approx 20MB each.  Once it has finished making\nthese unsorted files, it will sort them into the directory tree sorted/ and remove the\noriginal files.  It will then exit and you'll have your shiny table.\n\n\nTest with ht2crack2gentests\n---------------------------\n\n```\n./ht2crack2gentests NUMBER_OF_TESTS\n```\n\nto generate NUMBER_OF_TESTS test files.  These will all be named\nkeystream.key-KEYVALUE.uid-UIDVALUE.nR-NRVALUE\n\nTest a single test with\n\n```\n./runtest.sh KEYSTREAMFILE\n```\nor manually with\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n\nor run all tests with\n```\n./runalltests.sh\n```\n\nFeel free to edit the shell scripts to find your tools.  You might want to create a\nsymbolic link to your sorted/ directory called 'sorted' to help ht2crack2seach find the\ntable.\n\nIf the tests work, then the table is sound.\n\n\nSearch for key in real keystream\n--------------------------------\n\nRecover 2048 bits of keystream from the target RFID tag with the RFIDler.  You will have had\nto supply an NR value and you should know the tag's UID (you can get this using the RFIDler).\n\n```\n./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE\n```\n\n<!-- File: tools/hitag2crack/crack3/README.md (Tokens: ~212 | Category: plugin-manifest) -->\nht2crack3\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 136 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack3 UID NRARFILE\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\n\n\nTests\n-----\n\nIf you happen to know the key and want to check that all your nR aR values\nare valid (for high-powered demonstrations only, really) then you can use\nthe ht2crack3test program to check them.  It's otherwise massively pointless and a\ncomplete waste of space.\n\n```\n./ht2crack3test NRARFILE KEY UID\n```\n\n<!-- File: tools/hitag2crack/crack4/README.md (Tokens: ~195 | Category: plugin-manifest) -->\nht2crack4\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need a file consisting of 16 (or more) nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex with\none pair per line, e.g.:\n0x12345678 0x9abcdef0\n\n```\n./ht2crack4 -u UID -n NRARFILE [-N nonces to use] [-t table size]\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\nNRARFILE is the file containing the nR aR values.\nThe number of nonces to use allows you to use less than 32 nonces to increase\nspeed.\nThe table size can be tweaked for speed.  Start with 500000 and double it each\ntime it fails to find the key.\n\n<!-- File: tools/hitag2crack/crack5/README.md (Tokens: ~104 | Category: plugin-manifest) -->\nht2crack5\n\n\n\nBuild\n-----\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5 <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n\n<!-- File: tools/hitag2crack/crack5gpu_disabled/README.md (Tokens: ~130 | Category: plugin-manifest) -->\nht2crack5gpu\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5gpu <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n\n<!-- File: tools/hitag2crack/crack5opencl/README.md (Tokens: ~554 | Category: plugin-manifest) -->\nht2crack5opencl\n\n\n\nBuild\n-----\n\nIt requires an OpenCL framework.\n\nIf required, edit Makefile and adjust INCLUDE and LIBS directives to your setup.\n\n```\nmake clean\nmake\n```\n\nRun\n---\n\nYou'll need just two nR aR pairs.  These are the\nencrypted nonces and challenge response values.  They should be in hex.\n\n```\n./ht2crack5opencl <UID> <nR1> <aR1> <nR2> <aR2>\n```\n\nUID is the UID of the tag that you used to gather the nR aR values.\n\nUsage:\n\n```\n$ ./ht2crack5opencl\n./ht2crack5opencl [options] {UID} {nR1} {aR1} {nR2} {aR2}\n\nOptions:\n-p     : select OpenCL Platform(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-d     : select OpenCL Device(s). Multiple allowed (1,2,3,etc.). [Default: all]\n-D     : select OpenCL Device Type. 0: GPU, 1: CPU, 2: all. [Default: GPU]\n-S     : select the thread scheduler type. 0: sequential, 1: asynchronous. [Default 1]\n-P     : select the Profile, from 0 to 10. [Default: auto-tuning]\n-F     : force verify key with OpenCL instead of CPU. [Default: disabled]\n-Q     : select queue engine. 0: forward, 1: reverse, 2: random. [Default: 0]\n-s     : show the list of OpenCL platforms/devices, then exit\n-V     : enable debug messages\n-v     : show the version\n-h     : show this help\n```\n\nExample,\n\n```\nsimple\n\n./ht2crack5opencl 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n\nselect devices 1, 2 and 3 using platform 1 and 2, with random queue engine:\n\n./ht2crack5opencl -D 2 -Q 2 -p 1,2 -d 1,2,3 2ab12bf2 4B71E49D 6A606453 D79BD94B 16A2255B\n```\n\n\nYou can find the correct OpenCL Platform ID (-p) and Device ID (-d) with:\n\n```\n./ht2crack5opencl -s\n```\n\n<!-- File: tools/hitag2crack/README.md (Tokens: ~2315 | Category: plugin-manifest) -->\nHiTag2 Cracking Suite\n---------------------\n\nAuthors:\n\n* Attacks 1, 2, 3, 4 : Kevin Sheldrake <kev@headhacking.com>\n* Attacks 5, 5gpu : anonymous, based on https://github.com/factoritbv/hitag2hell by FactorIT B.V.\n* Attack  5opencl : Gabriele Gristina <gabriele.gristina@gmail.com>, based on 5gpu\n\nIntroduction\n------------\n\nThese tools are implementations of the four attacks detailed in the papers,\nGone In 360 Seconds - Hijacking With HiTag 2 by Roel Verdult, Flavio Garcia\nand Josep Balasch, and Lock It And Still Lose It - on the (In)Security of\nAutomotive Remote Keyless Entry Systems by Flavio Garcia, David Oswald,\nTimo Kasper and Pierre Pavlides.  The first three attacks come from the first\npaper and the fourth attack comes from the second paper.\n\n\n_note_\nThere are no Proxmark3 client implemented commands for these attacks. Only separate executables to be compiled and run on your own system.\nNo guarantees of working binaries on all systems.  Some work on linux only. \nThere is no easy way to extract the needed data from a live system and use with these tools.\nYou can use the `RFIdler` device but the Proxmark3 client needs some more love.  Feel free to contribute.\n\nAttack 1\n--------\n\nAttack 1 is a nonce replay and length extension attack.  This is an attack on\na single HiTag2 RFID tag, given a single encrypted nonce and challenge\nresponse value pair (nR, aR) for the tag's UID.  The attack runs entirely on\nthe Proxmark3 with it acting like a RWD that replays the same encrypted nonce\nand challenge response pair for every interaction; this fixes the key stream\nthat the tag's PRNG outputs to the same stream for every interaction.\n\nBy brute forcing a subset of the encrypted command space, the Proxmark3 finds a\nsingle valid encrypted command - invalid commands return a known unencrypted\nerror response so finding a valid one is simply a case of trying different\nvalues until a response other than the error response is received.\n\nIt then bit flips the valid encrypted command to find the other 15 valid\nencrypted commands.  By knowing the contents of page 0 - it's the UID that\nis presented in clear at the start of each interaction - it tries each\nencrypted response in turn, assuming each to be the encrypted version of\n'read page 0 non-inverted' and each response to be the encrypted version of\npage 0.\n\nFor each attempted command, it calculates the key stream that would have\ncorrectly generated the encrypted command and response:\ncommand ++ response XOR key stream = encrypted command ++ encrypted response\ntherefore:\nkey stream = command ++ response XOR encrypted command ++ encrypted response\n\nIt then tests the potentially recovered key stream by creating an encrypted\ncommand that consumes as much of it as possible, re-initialising with the same\nencrypted nonce and challenge response pair (to set the key stream to the\nsame stream as that which produced the encrypted command response it is\ntesting), and then sending this extended encrypted command.  If the response\nis not the error response, then the key stream is valid and the response is\nthe encryption of the page 0 contents (the UID).\n\nWhen one of the valid encrypted commands satisfies this situation, the\nrecovered key stream must be the output of the PRNG for the given encrypted\nnonce and challenge response pair.\n\nThe Proxmark3 then uses this key stream to encrypt commands and decrypt the\nresponses, and therefore requests the contents of all 8 pages.  Pages 1 and 2\ncontain the encryption key.\n\nAttack 2\n--------\n\nAttack 2 is a time/space trade off to recover the key for situations where the\ntag has been configured to prevent reading of pages 1 and 2.  This attack uses\na pre-computed table of 2^37 PRNG states and resultant PRNG output, sorted on\nthe PRNG output.  The Proxmark3 is used to recover 2048 bits of key stream using\na modification of attack 1 and this is used to search the table for matching\nPRNG output.  When the output is found, it is tested for validity (by testing\nprevious or following PRNG output) and then the PRNG state is rolled back to\nthe initialisation state, from which the unencrypted nonce and key can be\nrecovered.\n\nAttack 3\n--------\n\nAttack 3 is a cryptanalytic attack that focuses on the RWD and a bias in the\nPRNG output.  By capturing 136 encrypted nonce and challenge response pairs,\ncandidates for the first 34 bits of the key can be identified, and for each\nthe remaining 14 bits can be brute forced.\n\nAttack 4\n--------\n\nAttack 4 is a fast correlative attack on the key based on a number of captured\nencrypted nonce and challenge response pairs (up to 32, but 16 usually\nsufficient).  It starts by guessing the first 16 bits of the key and scores\nall these guesses against how likely they are to be the correct key, given the\nencrypted nonces and the keystream they should produce.  Each guess is then\nexpanded by 1 bit and the process iterates, with only the best guesses taken\nforward to the next iteration.\n\nAttack 5\n--------\n\nAttack 5 is heavily based on the HiTag2 Hell CPU implementation from https://github.com/factoritbv/hitag2hell by FactorIT B.V.,\nwith the following changes:\n\n* Main takes a UID and 2 {nR},{aR} pairs as arguments and searches for states producing the first aR sample, reconstructs the corresponding key candidates and tests them against the second nR,aR pair;\n* Reuses the Hitag helping functions of the other attacks.\n\nAttack 5gpu\n-----------\n\nAttack 5gpu is identical to attack 5, simply the code has been ported to OpenCL\nto run on GPUs and is therefore much faster than attack 5.\n\nAttack 5opencl\n--------------\n\nAttack 5opencl is an optimized OpenCL version based on 5gpu.\nIt runs on multi GPUs/CPUs and is faster than 5gpu.\n\nUsage details: Attack 1\n-----------------------\n\nAttack 1 requires a valid tag and a valid encrypted nonce and challenge\nresponse pair.  The attacker needs to obtain a valid tag and then use this to\nobtain a valid encrypted nonce and challenge response pair.  This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.   \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** example\n\n\nUsage details: Attack 2\n-----------------------\n\nAttack 2 requires the same resources as attack 1, plus a pre-computed table.\nThe table can be generated on a disk with >1.5TB of storage, although it takes\nsome time (allow a couple of days, privilege SSD). This can be\nachieved by using the Proxmark3 `lf hitag sniff` command, placing the coil on the RWD and\npresenting the valid tag.  The encrypted nonce and challenge response pairs\ncan then be read out.  \n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\n./ht2crack2gentest 1\n./runalltests.sh\n```\n\nUsage details: Attack 3\n-----------------------\n\nAttack 3 requires only interaction with the RWD and does not require a valid\ntag, although it does require a HiTag2 tag that the RWD will initially respond\nto; e.g. you could potentially use any HiTag2 tag as long as the RWD starts\nthe crypto handshake with it.  It requires >=136 encrypted nonce and challenge\nresponse pairs for the same tag UID.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n**TODO** will be ht2 sim or sniff with actual tag ?\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py 000102030405 AABBCCDD 32 > hitag2_AABBCCDD_nrar_32emul.txt\n./ht2crack3test hitag2_AABBCCDD_nrar_32emul.txt 000102030405 AABBCCDD\n./ht2crack3 AABBCCDD hitag2_AABBCCDD_nrar_32emul.txt |grep -E -v '(trying|partial)'\nrm hitag2_AABBCCDD_nrar_32emul.txt\n```\n\nUsage details: Attack 4\n-----------------------\n\nAttack 4 requires the same information as attack 3, but only 16-32 encrypted\nnonce and challenge response pairs are required.\n\n_note_  the Proxmark3 hitag sniff command isn't good enough yet to collect the needed data.\n\n#### Example\n```\npython3 ../hitag2_gen_nRaR.py AABBCCDDEEFF 12345678 32 > hitag2_12345678_nrar_32emul.txt\n./ht2crack4 -u 12345678 -n hitag2_12345678_nrar_32emul.txt -N 16 -t 500000 2>&1\nrm hitag2_12345678_nrar_32emul.txt\n```\n\nUsage details: Attack 5\n-----------------------\n\nAttack 5 requires two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5 12345678 71DA20AA 7EFDF3FA 2A4265F9 59653B07\n```\n\nUsage details: Attack 5gpu/5opencl\n----------------------------------\n\nAttacks 5gpu and 5opencl require two encrypted nonce and challenge\nresponse value pairs (nR, aR) for the tag's UID.\n\n#### Example\n```\n./ht2crack5opencl 12345678 B438220C 944FFD74 942C59E3 3D450B34\n```\n\n5opencl supports a number of additional parameters, see [crack5opencl/README.md](/tools/hitag2crack/crack5opencl/README.md) for details.\n\nUsage details: Next steps\n-------------------------\n\nOnce the key has been recovered using one of these attacks, the Proxmark3 can\nbe configured to operate as a RWD and will capture tags using that key.\n\n**TODO** example\n\nTags can be copied with standard Proxmark3 commands.\n\n**TODO** example\n\n<!-- File: tools/kgh/README.md (Tokens: ~661 | Category: plugin-manifest) -->\n# legic_kgh_tool\n\n## Running\n\n`legic_kgh_tool` reads KGH LEGIC card information, badge numbers, and stamps,\nand writes the supported KGH card layout.\n\nExamples:\n\n```bash\n./legic_kgh_tool COM13 read_badge_number\n./legic_kgh_tool COM13 read_info\n./legic_kgh_tool COM13 read_stamp\n./legic_kgh_tool COM13 read_stamp -o stamp.bin\n./legic_kgh_tool COM13 write_card 600001 --stamp-file stamp.bin\n```\n\nCommands:\n\n- `read_badge_number` prints the badge number only.\n- `read_info` prints one-line JSON.\n- `read_stamp` prints the stamp as 8 hex chars, or writes raw 4 bytes with `-o/--output-file`.\n- `write_card <badge> (--stamp-file <path> | --stamp-hex <8hex>)` writes the supported KGH layout.\n\nNotes:\n\n- Windows ProxSpace examples use `COM13`.\n- The stamp is 4 bytes and specific to your site.\n  It can be specified as a `.bin` file or as `--stamp-hex` (for example, `003EF417`).\n- You can retrieve the stamp from a supported KGH card with `read_info` or `read_stamp`.\n- Linux examples usually use `/dev/ttyACM0` or similar.\n- `--verbose` can be useful for `read_badge_number` and `write_card`, if they fail for mysterious reasons.\n\n## Building in ProxSpace (for Windows)\n\nDo this in ProxSpace:\n\n```bash\ncd ~/proxmark3/tools/kgh\nrm -rf build-lite\ncmake -G \"MSYS Makefiles\" -S . -B build-lite \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-lite --target legic_kgh_tool -j\nobjdump -p build-lite/legic_kgh_tool.exe | grep -i \"DLL Name\"\n```\n\n## Building Linux\n\n```bash\ncd tools/kgh\nrm -rf build-linux\ncmake -S . -B build-linux \\\n  -DSKIPPYTHON=1 \\\n  -DSKIPREADLINE=1 \\\n  -DSKIPJANSSONSYSTEM=1 \\\n  -DSKIPWHEREAMISYSTEM=1 \\\n  -DSKIPBT=1\ncmake --build build-linux --target legic_kgh_tool -j\nldd build-linux/legic_kgh_tool\n```\n\n## Static Link Notes\n\n- `legic_kgh_tool` is linked against `pm3rrg_rdv4_static`.\n- On MinGW, CMake adds `-static -static-libgcc` for the target.\n- Linux builds are not the same as the ProxSpace single-EXE deployment.\n- If CMakeCache paths change between ProxSpace and a native shell, delete the build dir and reconfigure.\n</yakaai_skills>"}