Security and recovery practices

Fractum can encrypt a file and split its key, but it cannot choose trustworthy custodians, keep copies separated, or make a recovery plan understandable years later. Those decisions determine whether a K-of-N setup is useful in practice.

1. Decide the threshold before creating shares

Write down the answer to these questions before choosing K and N:

  • How many people or locations can reliably be reached during recovery?
  • How many shares may be unavailable without losing recovery?
  • Must one person be unable to recover the file alone?
  • Who is allowed to initiate recovery, and how will that be confirmed?

A 3-of-5 arrangement, for example, can tolerate two missing shares but still requires three compatible shares to assemble. It is a starting point, not a universal recommendation. Keep K low enough that an ordinary recovery still works when a custodian is unreachable or a location is temporarily inaccessible.

2. Separate the recovery material

The encrypted .enc file and every share archive are parts of the recovery workflow. Avoid keeping all of them in one account, device, location, or envelope.

Material Practical handling question
Encrypted file Where can it be retained so it is available during recovery?
Share archive or share value Which independent custodian or location holds it?
Threshold and instructions Can the authorised recoverer find the procedure without also receiving every share?
Fractum runtime Can the recovery machine obtain the expected tool version without relying on an unavailable service?

Record enough information to run a recovery: file identity, chosen K, locations or custodians, and a contact process. Do not place all share values into that record.

3. Rehearse recovery while the setup is fresh

  1. Encrypt a disposable file with the intended K and N values.
  2. Place the generated archives in the same separate locations you would use in a real workflow.
  3. Recover it using only K of those archives on the intended recovery machine.
  4. Compare the recovered file with the original.
  5. Update the written procedure when any step was unclear or unavailable.

Repeat the drill after a custodian changes, storage is moved, a tool version changes, or the recovery instructions are revised.

4. Operate with a clean boundary

For sensitive operations, consider a dedicated or otherwise controlled machine, minimise unrelated applications, and understand the storage and swap behaviour of that environment. Docker can be run with --network=none, but this is a Docker flag you choose for each run; it does not replace host integrity or physical controls.

The current implementation makes best-effort attempts to clear mutable key buffers. That is defence in depth, not a guarantee that every copy in memory, swap, crash dumps, or hardware is erased. Read the security architecture before setting a high-value threat model.

5. Verify the software you intend to run

Use the upstream repository and published release material. When a release provides a signature, import the published signing key and compare its fingerprint before trusting the result:

curl -O https://fractum.katvio.com/fractum-signing-key.asc
gpg --import fractum-signing-key.asc
gpg --fingerprint D009F6290DCFDAB6

Expected fingerprint: 179D F24B 6E6E 3D8A EFD9 A795 D009 F629 0DCF DAB6.

When you are online, cross-check the bundled Python wheels against the hashes published by PyPI before relying on the offline package bundle:

cd fractum
python3 - <<'PY'
import hashlib
import json
import pathlib
import urllib.request

packages = pathlib.Path("packages")
for wheel in sorted(packages.glob("*.whl")):
    name, version = wheel.name.split("-")[:2]
    with urllib.request.urlopen(f"https://pypi.org/pypi/{name}/{version}/json") as response:
        release = json.load(response)

    published = next(
        (file for file in release["urls"] if file["filename"] == wheel.name),
        None,
    )
    if published is None:
        raise SystemExit(f"{wheel.name}: not found on PyPI")

    expected = published["digests"]["sha256"]
    actual = hashlib.sha256(wheel.read_bytes()).hexdigest()
    if actual != expected:
        raise SystemExit(
            f"{wheel.name}: SHA-256 mismatch\n"
            f"  local: {actual}\n"
            f"  PyPI:  {expected}"
        )
    print(f"OK {wheel.name} {actual}")
PY
(cd packages && sha256sum --check CHECKSUMS.sha256 --strict)

The Python command asks PyPI for each bundled wheel filename and compares the local SHA-256 with the digest PyPI publishes for that exact file. The final command checks that the repository's local CHECKSUMS.sha256 file matches the same package files. Run these checks before moving a machine offline.

Software verification supports a recovery plan; it does not replace a recovery rehearsal. The FAQ and security architecture describe Fractum's scope and current limits.