Hardware-grade PIN security — without the hardware.
A 4-digit PIN has only 10,000 combinations. Anywhere it guards data an attacker can copy — a browser, a file, a backup — they can brute-force it offline in milliseconds. VESlocker removes the offline attack entirely: the decryption key is split between the user's PIN and a secret held by a small key server, released only under a strict, exponentially-throttled budget. After a few dozen wrong guesses the entry is locked for good — a true lifetime cap on attempts, the way a TPM or a secure enclave behaves, in ~250 lines of vanilla JS and ~110 lines of PHP.
challenge = SHA-256(seed ‖ PIN) and sends only an id and that challenge to the key server — never the seed, the PIN, or the data.id secret, enforces the throttle (the next attempt is refused for 2^attempts seconds, capped), and returns key = SHA-256(secret ‖ challenge).AES-GCM(key). The ciphertext and the seed are kept locally; the key itself is never stored.id increments its counter. After ~32 attempts the wait exceeds a century — the entry is effectively sealed.<script src="https://veslocker.com/pub/VESlocker.js"></script>
<script>
const vl = new VESlocker({
apiUrl: "https://veslocker.com/api/VESlocker.php"
});
// Encrypt a secret behind a PIN and stash it under a name:
await vl.store("launch-codes", "1234", "the actual launch codes");
// Read it back with the PIN - throttled, and re-deposited under a
// fresh id + seed on every success:
const secret = await vl.fetch("launch-codes", "1234");
</script>
The client is Apache-2.0 — embed it with no copyleft obligations.
Prefer to manage storage yourself? encrypt / decrypt are stateless and return / take a self-contained token.
This demo talks to the public veslocker.com key server. Store a value behind a PIN, then fetch it back — and watch the throttle kick in after a few wrong PINs.
VESlocker isn't a new cryptographic protocol — it's a deliberately minimal take on a known idea: harden a low-entropy PIN with the help of a key server, so it can't be brute-forced offline. Here's how it sits next to the rigorous prior art.
The server is unauthenticated by design — no accounts, no API keys. The only credential is the entry's id: 32 random bytes (256 bits). You can't throttle-attack, or even address, an entry whose id you don't hold. The id is a bearer capability, not an identity.
| What it's for | Trust anchor | Hard lifetime guess cap | No special hardware | Survives a malicious operator | |
|---|---|---|---|---|---|
| VESlocker | Decrypting local data behind a PIN | Server operator + availability | ✓ exponential, ~century | ✓ any PHP host + Web Crypto | ✗ by design |
| OPAQUE / aPAKE | Login / session key agreement | Server operator | ✗ needs bolt-on rate limiting | ✓ | partial |
| Signal SVR | PIN-recovering a stored secret | Hardware enclave (SGX) + attestation | ✓ destroy-after-N | ✗ needs SGX | ✓ |
| Pythia / PHE | Hardening + rotatable password keys | Server key (rotatable) | ✗ focus is rotation | ✓ | partial |
Read the table by its one standout cell: among the systems compared here, VESlocker is the only row that's a check in both “hard lifetime guess cap” and “no special hardware.” Signal's SVR gets the cap by putting the throttle inside a secure enclave; OPAQUE and Pythia run on commodity servers but have no built-in attempt limit. VESlocker gets both by enforcing the throttle in ordinary application code — the trade-off being the last column: it trusts the operator, where an enclave would not.
VESlocker is a key oracle gated by throttling, not a vault. Reason about it honestly before you deploy:
veslocker.com API endpoint and public JS library, as shown above.