import fs from "fs"; import path from "path"; import { HEADER_MAGICS } from "./constants"; import { desDecryptBlock, desDecryptFile, hexKeyToBuffer } from "./des"; export interface HitRecord { cipher: "des"; password: string; derivation: string; key_hex: string; pad_fill: string; first_pt_hex: string | null; backend: string; payload_ok?: boolean; payload_reason?: string; first64_ascii?: string; decrypt_error?: string; } export function payloadLooksReal(first64: Buffer, more?: Buffer): { ok: boolean; reason: string } { for (const magic of HEADER_MAGICS) { if (first64.subarray(0, magic.length).equals(magic) || first64.includes(magic)) { return { ok: true, reason: "magic" }; } } let printable = 0; for (const b of first64) { if ((b >= 32 && b < 127) || b === 9 || b === 10 || b === 13) { printable++; } } if (printable >= 48) { return { ok: true, reason: "printable_header" }; } const blob = Buffer.concat([first64, more ?? Buffer.alloc(0)]); if (blob.includes(Buffer.from("Butcher")) || blob.includes(Buffer.from("Thomas")) || blob.includes(Buffer.from("Pectus")) || blob.includes(Buffer.from("Torso"))) { return { ok: true, reason: "patient_string" }; } let inRange = 0; for (let i = 0; i + 4 <= first64.length; i += 4) { const f = first64.readFloatLE(i); if (Number.isFinite(f) && Math.abs(f) < 5000) { inRange++; } } if (inRange >= 12) { return { ok: true, reason: "float32_scan_range" }; } const count = first64.readUInt32LE(0); if (count >= 1000 && count <= 200_000) { return { ok: true, reason: `vertex_count_${count}` }; } return { ok: false, reason: "unstructured" }; } export function asciiPreview(buf: Buffer): string { return [...buf].map((b) => (b >= 32 && b < 127 ? String.fromCharCode(b) : ".")).join(""); } export function saveHit(hit: HitRecord, data: Buffer, outDir: string): string | null { fs.mkdirSync(outDir, { recursive: true }); const key = hexKeyToBuffer(hit.key_hex); try { const plain = desDecryptFile(key, data); const first64 = plain.subarray(0, 64); const more = plain.subarray(0, 4096); const check = payloadLooksReal(first64, more); hit.payload_ok = check.ok; hit.payload_reason = check.reason; hit.first64_ascii = asciiPreview(first64); const stamp = `${hit.cipher}_${hit.derivation}_${hit.key_hex.slice(0, 16)}`; const binPath = path.join(outDir, `decrypted_${stamp}.bin`); fs.writeFileSync(binPath, plain); fs.writeFileSync(path.join(outDir, `hit_${stamp}.json`), JSON.stringify(hit, null, 2) + "\n"); return binPath; } catch (err) { hit.decrypt_error = err instanceof Error ? err.message : String(err); return null; } } export function firstPlainHex(keyHex: string, firstCt: Buffer): string | null { try { const pt = desDecryptBlock(hexKeyToBuffer(keyHex), firstCt); return pt.toString("hex"); } catch { return null; } } export function writeResults(outDir: string, elapsedSec: number, hits: HitRecord[]): void { fs.mkdirSync(outDir, { recursive: true }); const confirmed = hits.filter((h) => h.payload_ok); fs.writeFileSync( path.join(outDir, "results.json"), JSON.stringify({ elapsed_sec: Math.round(elapsedSec * 1000) / 1000, pad_matches: hits, confirmed }, null, 2) + "\n", ); }