Targeting August 1, 2026. RVNT is a pre-release, self-funded project built by a small team — full transparency, that’s one developer going hard. Not yet security-audited. Back the build & shape it →

Argon2id: How a 6-Digit PIN Becomes an Unbreakable Key

argon2pin-authenticationkey-derivationencryptionsqlcipher

A six-digit PIN has exactly one million possible values. Written down, that is a list you could print in an afternoon and check in an instant. So how can the same six digits stand between an attacker and an entire encrypted message history sitting on a seized phone? The honest answer is that the PIN alone can’t — not the way most apps use it. The trick is to make each guess expensive: not in clever math, but in raw memory and time. That is the entire job of Argon2id, the password-hashing function RVNT runs to turn your PIN into the key that unlocks its local database. It does not make your PIN secret. It makes guessing your PIN slow enough, and hardware-hungry enough, that a million tries stops being trivial.

This post is about the gap between “a PIN that authenticates you” and “a PIN that is the key,” why that distinction decides whether your data survives a forensic lab, and exactly how RVNT derives a 256-bit SQLCipher key from a handful of digits. We’ll also be straight about the limits — because a 6-digit PIN is genuinely brute-forceable, and pretending otherwise would be the kind of hype this project refuses to ship.

The PIN is the key, not the password

In a typical app, your PIN authenticates you. The real encryption key lives somewhere else — a keychain entry, a server, a file — and the app compares your PIN against a stored value, then hands you the key if they match. The problem is structural: anyone who can read that key storage skips the PIN entirely. A forensic tool that dumps the keychain, a malicious sync server, a backup that wasn’t supposed to include the key — any of these bypasses your six digits without ever guessing them.

RVNT inverts this. As the PIN authentication docs put it bluntly: your PIN is not a password, it is the encryption key. There is no separately stored key to steal. The PIN is the sole input to a key derivation function whose output opens the database. No server knows it. There is no “forgot PIN” recovery path, because a recovery path is, by definition, a second door into your data.

PIN → Argon2id → database_key → SQLCipher(AES-256). There is no other path to the data. The key exists only in memory while the app is unlocked, and is zeroed when it locks.

This is also why the key derivation has to be good. When the PIN is the key, the strength of the function that stretches it is the strength of your encryption at rest. A weak hash here doesn’t just slow an attacker down — it hands them the database.

Why a fast hash would be a disaster

Suppose RVNT derived the key with a single round of SHA-256, the way a careless app might. SHA-256 is built to be fast — that is its whole purpose as a hash function. A modern GPU computes it billions of times per second. Against a 6-digit PIN’s one million candidates, an attacker who has your encrypted database and your salt would finish the entire keyspace in well under a millisecond. The encryption would be theater.

Even classic iterative stretching — PBKDF2 with hundreds of thousands of rounds, which is what SQLCipher itself uses internally on the key you give it — only buys time linearly, and it buys it cheaply for the attacker. PBKDF2 is almost pure arithmetic with a tiny memory footprint. That means an adversary can pack thousands of independent PBKDF2 pipelines onto one GPU, or etch them into a custom ASIC for pennies of silicon each, and parallelize their way through your keyspace. Iteration count raises the cost for you and the attacker by the same factor; it does nothing to stop the attacker from buying a thousand times more parallelism than you can.

That asymmetry — cheap to parallelize — is the weakness memory-hardness was invented to close.

Memory-hardness: making silicon the bottleneck

Argon2 won the Password Hashing Competition in 2015, an open, AES/SHA-3-style public contest, precisely because it attacked the parallelism problem head-on. It was later standardized in RFC 9106, which specifies three variants. RVNT uses Argon2id, the hybrid the RFC names as the one that MUST be supported: it runs the data-independent Argon2i logic over the first half of the first pass (for side-channel resistance) and the data-dependent Argon2d logic for the rest (for maximum brute-force cost).

The core idea is memory-hardness. To compute one Argon2id hash with RVNT’s settings, the algorithm fills and repeatedly re-reads a large block of RAM — 64 MB of it — in a pattern that depends on the data it’s processing. You can’t shortcut it. You can’t recompute pieces on the fly to save space without paying a brutal time penalty. To run one guess, you must dedicate 64 MB of working memory.

Now run the attacker’s math. A high-end GPU with 24 GB of VRAM sounds enormous — until you divide by 64 MB per attempt and discover it can hold only about 375 Argon2id computations at once. The thing that used to give GPUs and ASICs their crushing advantage — thousands of parallel lanes — is now capped not by arithmetic units but by memory bandwidth and capacity, the most expensive resource on a chip. As RFC 9106 notes, Argon2 is deliberately tuned to “exploit the cache and memory organization of recent Intel and AMD processors,” the very structures that custom attack hardware lacks. Memory is the great equalizer: the defender’s laptop and the attacker’s rack pay roughly the same per-guess memory cost, and that cost is high.

How RVNT derives the key

Here are the exact parameters RVNT uses, straight from the PIN docs:

ParameterValueWhy
Memory (m)65536 KB (64 MiB)Memory-hard: caps GPU/ASIC parallelism
Iterations (t)3Time cost, ~300 ms on modern hardware
Parallelism (p)4Parallel lanes
Output32 bytesA 256-bit key
Salt32 random bytes, per deviceDefeats rainbow tables and shared precomputation
VersionArgon2id v1.3RFC 9106

Those numbers are not arbitrary — t=3, p=4, m=2^16 (64 MiB) is exactly the second recommended configuration in RFC 9106, the profile the standard offers for memory-constrained environments like phones. (The RFC’s first option asks for 2 GiB, which is fine on a desktop but punishing on a mobile device that has to do this on every unlock.)

The 32-byte salt, generated once per device at identity creation and stored alongside the data, matters more than it looks. Without it, every RVNT user with the same PIN would derive the same key, and an attacker could precompute a single table of PIN → key once and reuse it against everyone. The salt forces the attacker to start from scratch for each device — no rainbow tables, no shared work.

The raw Argon2id output isn’t used directly as one master key. RVNT runs it through HKDF-SHA256 to split it into purpose-bound subkeys — a database key, a backup key, an export key — so that one role can never be confused for another, and the raw key is securely zeroed immediately after. The database key then opens the SQLCipher store, which wraps it in its own AES-256 + HMAC layer for encryption at rest. When the app locks, every derived key is wiped from memory; the only way back in is to enter the PIN and pay the Argon2id cost again.

The honest limits of six digits

Here is where we refuse to oversell. Memory-hardness raises the cost per guess; it does not make a small keyspace large. Do the arithmetic with RVNT’s own numbers. At roughly 375 parallel attempts on a 24 GB GPU and ~300 ms each, an attacker manages on the order of ~1,250 guesses per second:

  • 6-digit PIN (10⁶ candidates): exhausted in ~13 minutes.
  • 8-digit PIN (10⁸): ~22 hours.
  • 10-digit PIN (10¹⁰): ~93 days.
  • Alphanumeric, 8 characters (62⁸ ≈ 2×10¹⁴): thousands of years.

So a 6-digit PIN protects you against a thief who grabs your phone, a nosy acquaintance, an opportunistic forensic dump by someone who won’t invest in a GPU rig. It does not protect you against a determined, well-funded adversary who has both your encrypted database and your salt and is willing to spend GPU time. The fix is in your hands: every extra digit multiplies the attack time by ten, and switching to an alphanumeric passphrase blows the cost out to geologic timescales.

RVNT stacks two more defenses on top. An escalating lockout — backed by the Secure Enclave or StrongBox where available, so reinstalling the app doesn’t reset it — turns even an online attack against the running app into days of forced waiting. And a duress PIN gives you a second key that destroys the real cryptographic material and presents decoy data instead, for the moment when the threat isn’t a brute-force rig but a person demanding you unlock.

To be clear about RVNT’s status: it is pre-release software and has not been independently audited. The parameters above are real and documented, but the right posture toward any encryption claim — ours included — is to verify it, not trust it.

A six-digit PIN will never be “unbreakable” in the literal sense; one million is a finite number. What Argon2id does is change the units of breaking from microseconds to minutes, and from cheap parallel silicon to expensive memory bandwidth — and it hands you a dial, length, that turns minutes into millennia. Spend a few extra digits. The whole design is built so that your effort, not a server’s promise, is what keeps the data shut.

Keep reading

All posts →