How CronosPro's KOD cipher was cracked with the Hungarian algorithm

How CronosPro's KOD cipher was cracked with the Hungarian algorithm

A data engineering team that normalizes incoming datasets into a data lake received a set of CronosPro database files, CroBank.dat, CroIndex.dat and CroStru.dat, that existing tooling could not parse and that were assumed to be broken. CronosPro is a proprietary desktop database and information-management system used historically by organizations in Russia and other post-Soviet countries to build registries, archives and internal document systems. The team started from the open-source Cronodump parser (alephdata/cronodump on GitHub) and, with help from OpenAI's Codex for analyzing the dump structure, extended that codebase to fix parsing of this particular dump.

Header inspection showed the dump used the Cronos 01.11 format, associated with Cronos v4, and that only CroStru.dat, the schema file, was KOD-encoded; CroBank.dat and CroIndex.dat were compressed but not KOD-encoded. That narrowed the problem: only the relatively small schema file needed its protection cracked, since once it was readable the ordinary parser could interpret the much larger record file. KOD protection works by running each byte through a 256-entry substitution table (the KOD table, or KOD S-box), with decoding also depending on the byte's position in the record and the record number: plaintext[i] = KOD[ciphertext[i]] minus i minus the record number, wrapped modulo 256. Being off by even one byte in the table corrupts the decoding of everything that follows.

Cronodump already ships two heuristic recovery tools, strucrack and dbcrack, both of which infer the KOD table from statistical properties of the files rather than by brute-forcing a password: strucrack looks for the most common decoded byte at each position and assumes it represents plaintext zero, while dbcrack infers mappings from predictable bytes in compressed-record headers. Neither applied cleanly here: CroStru held too little evidence for strucrack to recover every table entry reliably, and dbcrack was inapplicable since CroBank and CroIndex were not KOD-encoded at all. The team also had to patch a small software bug in the cracking code paths, a temporary argument object missing a required compact property, fixed by adding cargs.compact = args.compact, before the heuristics would run at all.

The team found an unmerged upstream cronodump branch, pull request #22 (erdgeist-strucrack-ambigous-kods), which adds an interactive workflow for resolving ambiguous KOD entries by tracking confidence per entry, flagging duplicates, and letting an operator supply known-plaintext hints. That branch did not appear to address several problems the team still faced: a Cronos v4 inline-record header that shifted decoding, hidden physical fields inside records, and incorrect handling of documented text field types. So the team built its own automated approach instead. Using a smaller, already-readable Cronos test database bundled with the cronodump repository, they estimated the general byte-frequency distribution of valid Cronos schema data (many zero bytes, small binary integers, length-prefixed names, ASCII property names, Windows-1251 text, repeated structure markers). For every encrypted byte in the unknown schema they knew its ciphertext value, its position, and its record number, and could score how plausible each possible KOD mapping was against that reference distribution, producing a 256-by-256 score table.

Because a KOD table must be a strict permutation, one where every ciphertext byte maps to exactly one output value and no two ciphertext bytes may share an output, the team could not just pick the highest-scoring mapping independently for each byte. They treated this as a classic assignment problem and solved it with SciPy's implementation of the Hungarian algorithm, calling linear_sum_assignment on the negated score matrix (since the function minimizes cost rather than maximizes score). The result was a complete 256-byte KOD permutation, a candidate key that the team then began validating structurally rather than trusting because the decoded output looked readable, noting that a wrong substitution can still accidentally produce letters, digits or familiar fragments. The available text of the article ends mid-sentence during the description of that structural validation step, so the final confirmation of the recovered table and the rest of the conversion pipeline are not covered here.

Key facts

  • A team could not parse CronosPro dump files (CroBank.dat, CroIndex.dat, CroStru.dat) with existing tools and used the open-source Cronodump parser, extended with help from OpenAI's Codex, to recover them.
  • The dump used the Cronos 01.11 format (Cronos v4); only the schema file CroStru.dat was KOD-encoded, while CroBank.dat and CroIndex.dat were compressed but not KOD-encoded.
  • Cronos KOD protection substitutes bytes through a 256-entry table with position- and record-dependent decoding: plaintext[i] = KOD[ciphertext[i]] minus i minus the record number, mod 256.
  • Cronodump's existing strucrack and dbcrack heuristics could not fully crack this dump, so the team scored every possible byte mapping against reference Cronos schema statistics and solved the table as an assignment problem with SciPy's Hungarian algorithm (linear_sum_assignment).
  • The solve produced a complete 256-byte KOD permutation, which the team began validating structurally rather than trusting on readability alone, since a wrong substitution can still produce letters or digits that look plausible.

Why it matters

The story is a worked example of turning a broken, undocumented binary format back into something reviewable, without any leaked KOD table or documentation to start from. The key move is treating cipher recovery as a constrained optimization problem: instead of guessing byte mappings one at a time, the team scored every possible substitution against known Cronos byte statistics and let the Hungarian algorithm pick the globally best permutation that still respects the one-to-one constraint a substitution table requires. That combination of statistical scoring plus assignment-problem solving is a reusable technique well beyond this one database format.

Who it affects

Most directly, this is relevant to data engineers, archivists and researchers who still hold legacy CronosPro databases, a format historically used by organizations in Russia and other post-Soviet countries for registries, archives and internal document systems, and who rely on the open-source Cronodump project (alephdata/cronodump) to get that data out. It also matters to anyone maintaining or extending Cronodump itself, since the team's fixes and the related unmerged pull request #22 target the same class of KOD-recovery weaknesses.

How to use it

The recovery builds directly on the open-source Cronodump tool's crodump and croconvert commands, plus its existing strucrack and dbcrack cracking heuristics. Where those heuristics fall short, as they did on CroStru.dat here, the described method is to estimate byte-frequency statistics from a known-good Cronos schema sample (Cronodump ships a small test database for this), score each possible KOD mapping against that reference, and solve for the best full permutation with SciPy's linear_sum_assignment. The team also notes a specific bug fix needed in the cracking code path: a temporary argument object missing a required compact property, resolved with cargs.compact = args.compact.

How solid is it

The account is a first-hand technical walkthrough with specific file names, format-version numbers, code, and the exact decoding formula used, which supports its credibility. The team is explicit that a complete KOD permutation is only a candidate key until validated structurally, since decoded output that merely looks readable is weak evidence: a wrong substitution can still coincidentally produce letters or digits. The text available for this summary ends mid-sentence during that structural validation step, so whether the recovered table was ultimately confirmed correct, and how the rest of the conversion to CSV proceeded, is not covered here.

Risks and caveats

The KOD decoding formula is position- and record-number-dependent, so the article stresses that being off by even one byte in the table changes the decoding of everything that follows, which is why the team treated a successful-looking decode as only a starting hypothesis. The statistical scoring approach also depends on having a representative reference sample of valid Cronos schema data; with too little evidence, as was the case for parts of this schema, purely heuristic tools like strucrack could not resolve every table entry on their own.

“A wrong substitution can accidentally produce letters, digits, or familiar fragments.”

— the blog post