Skip to content

vesvault/VESlocker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
          ___       ___
         /   \     /   \    VESvault
         \__ /     \ __/    Encrypt Everything without fear of losing the Key
            \\     //                   https://vesvault.com https://ves.host
             \\   //
     ___      \\_//
    /   \     /   \         VESlocker:        Hardware-grade PIN Security API
    \__ /     \ __/
       \\     //                                        https://veslocker.com
        \\   //
         \\_//
         /   \
         \___/

VESlocker — Hardware-grade PIN Security API

CI client: Apache-2.0 server: PolyForm Perimeter live demo

Give a short PIN the strength of a hardware security module — without the hardware.

A 4-digit PIN has only 10,000 combinations. Anywhere it guards data that 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, and the server hands the key back 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, implemented in ~250 lines of vanilla JS and ~110 lines of PHP.

🔎 Try it: there is a live demo at veslocker.com.


How it works

  client                                            key server
  ──────                                            ──────────
  challenge = SHA-256(seed ‖ PIN)  ───── id, challenge ─────▶  look up per-id secret
                                                               throttle check (2^attempts)
  key = AES-GCM key  ◀──── SHA-256(secret ‖ challenge) ──────  return derived key
  ciphertext = AES-GCM(key, data)
  (ciphertext + seed are stored locally; the key is never stored)
  • The data is encrypted client-side with AES-GCM. The key is derived from the server's per-entry secret and a challenge seeded by the user's PIN.
  • The server never receives the seed, the PIN, the plaintext, or the ciphertext — only an id and a challenge (a hash). It returns the derived key, gated by throttling.
  • Each request to an id increments an attempt counter; the next request is refused until 2^attempts seconds have passed (capped at 32). After ~32 attempts the wait exceeds a century — the entry is effectively sealed.

Quickstart

Client

<script src="client/VESlocker.js"></script>
<script>
  const vl = new VESlocker({
    apiUrl: "https://your-key-server.example/VESlocker.php"
  });

  // Encrypt a secret behind a PIN and stash it in localStorage under a name:
  await vl.store("launch-codes", "1234", "the actual launch codes");

  // Later — read it back with the PIN:
  const secret = await vl.peek("launch-codes", "1234");   // "the actual launch codes"

  // Re-encrypt under a new PIN (and refresh the stored token):
  await vl.fetch("launch-codes", "1234", "5678");
</script>

Prefer to manage storage yourself? encrypt / decrypt are stateless and return / take a self-contained token:

const token = await vl.encrypt("1234", "the actual launch codes");
const back  = await vl.decrypt("1234", token);   // "the actual launch codes"

Get notified when an entry's key is accessed (an early-warning signal that someone is guessing the PIN):

vl.accessFn = (id, count, at) => {
  if (count > 0) console.warn(`VESlocker '${id}' accessed ${count}× (last: ${at})`);
};

Key server

  1. Serve server/VESlocker.php behind any PHP-capable HTTP server.
  2. Create the database table from server/VESlocker.sql.
  3. Set the $DB* connection settings at the top of VESlocker.php.
  4. Point the client's apiUrl at it.

Requirements — Server: PHP + MySQL/MariaDB. Client: any browser with Web Crypto (all current browsers).

Security model

VESlocker is a key oracle gated by throttling, not a vault. Reason about it honestly before you deploy:

  • The server cannot read your data. It never sees plaintext or ciphertext — only an id and a challenge hash.
  • No offline brute force. An attacker who copies the ciphertext cannot test PINs offline: the key also requires the server's secret, which they don't have.
  • Hard lifetime cap on online guesses. Exponential per-id throttling limits an attacker (and the legitimate user) to roughly 32 attempts, ever.
  • ⚠️ Availability dependency. Decryption requires the key server to be reachable. This is by design — it is what makes the throttle unavoidable.
  • ⚠️ Two-secret compromise. If an attacker obtains both the server-side secret store and the ciphertext, the PIN can be brute-forced offline (bounded only by PIN entropy). Protect the key server's database accordingly, and treat the PIN's entropy as your last line of defense in that scenario.

Found a vulnerability? See SECURITY.md — please report privately.

License

VESlocker is licensed per component:

Component License
client/ Apache License 2.0 Embed it in your app with no copyleft obligations.
server/ PolyForm Perimeter 1.0.1 Use, modify, and self-host for any purpose — except offering a product that competes with VESlocker.

Contributing

Contributions are welcome under the DCO — see CONTRIBUTING.md. In short: sign off your commits with git commit -s.


Part of the VESvault project — Encrypt Everything without fear of losing the Key.

About

Hardware-grade PIN Security API

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors