Keys and licensing
Obfy has two independent mechanisms that are easy to confuse:
- The build key — the AES-256-GCM key that encrypts your code. Required to run a protected dist.
- The license file — optional terms (expiry, machine binding) baked into the dist and enforced by the runtime at import time.
Per-developer seat licensing (who may run
obfy build) is separate again — see Seats and devices.
The build key
Each build uses one AES-256-GCM key. By default it's written to
<out>/code.key and read from there at run time.
obfy build --src ./app --out ./dist --key ./secrets/build.key
-
Never commit
code.key. Obfy's defaults keep it out of your source tree; keep it out of version control on your side too. -
To keep the key out of the shipped dist entirely, delete
code.keyafter building and provide it out-of-band at run time via theOBFY_KEYenvironment variable (hex-encoded):OBFY_KEY=<hex-key> python ./dist/run.py
The license file
Pass --license with a JSON file to bind a build to specific conditions. The
terms are encrypted into the dist; the verdict runs in the native runtime and is
enforced by the loader at import time, with no network calls — everything is
measured locally.
obfy build --src ./app --out ./dist --license ./license.json
{
"expires": "2026-12-31",
"machines": ["00:11:22:33:44:55"],
"hostnames": ["build-server-01"],
"disks": ["WD-1234567890"],
"anti_rollback": true
}
| Field | Meaning |
|---|---|
expires | Date (YYYY-MM-DD) after which the dist refuses to run. |
machines | Allowed MAC addresses. |
hostnames | Allowed hostnames. |
disks | Allowed disk serial numbers. |
anti_rollback | Seals a clock-rollback floor so the expiry can't be bypassed by setting the system clock back. |
Every binding field you include must match for the dist to run. Omit a field to leave that dimension unconstrained.
Hardening flags
| Flag | Effect |
|---|---|
--anti-debug | The loader refuses to decrypt under an attached tracer (Linux TracerPid, macOS P_TRACED). Off by default so normal builds still run under your own pdb/coverage. |
--anti-tamper | Seals the plaintext loader and manifest.json under the build key; the runtime refuses to decrypt unless the on-disk copies still match. |
Both are deterrence, not prevention — a patched native runtime can still defeat them.