JSON v3 · 12 min read

Ethereum Keystore (JSON v3) Recovery

Your UTC--2018-07-01T...json file. What is in it, why Scrypt makes recovery painfully slow, and what a realistic attack pipeline looks like in 2026.

The Ethereum keystore v3 format

Defined in the original Web3 Secret Storage spec, v3 is a JSON document with a deliberate, memory-hard KDF.

{
  "version": 3,
  "id": "3198bc9c-6672-5ab3-d995-4942343ae5b6",
  "address": "008aeeda4d805471df9b2a5b0f38a0c3bcba786b",
  "crypto": {
    "ciphertext": "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46",
    "cipherparams": { "iv": "6087dab2f9fdbbfaddc31a909735c1e6" },
    "cipher": "aes-128-ctr",
    "kdf": "scrypt",
    "kdfparams": {
      "dklen": 32,
      "salt": "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd",
      "n": 262144,
      "r": 8,
      "p": 1
    },
    "mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2"
  }
}

Why Scrypt is so slow on purpose

Scrypt (Colin Percival, 2009) was designed as a memory-hard KDF specifically to make GPU and ASIC attacks expensive. The parameters in the keystore above — N=262144, r=8, p=1 — mean each password guess requires:

  • Allocating 128 × N × r = 128 × 262,144 × 8 = 256 MB of working memory
  • Filling that memory with a pseudorandom mixing function
  • Performing N dependent random-access reads

Because modern GPUs have limited VRAM per core, Scrypt kills parallelism. An RTX 4090 with 24 GB VRAM can run at most ~80 parallel guesses. Compare that to MD5 where the same GPU runs 160 billion parallel guesses.

Decryption algorithm

# Python pseudocode for verifying a keystore password
import scrypt, hashlib
from Crypto.Cipher import AES

def verify(password, keystore):
    k = keystore["crypto"]
    salt = bytes.fromhex(k["kdfparams"]["salt"])
    derived = scrypt.hash(
        password.encode(),
        salt,
        N=k["kdfparams"]["n"],
        r=k["kdfparams"]["r"],
        p=k["kdfparams"]["p"],
        buflen=k["kdfparams"]["dklen"],
    )
    # MAC check: first verify without decrypting
    mac = hashlib.sha3_256(derived[16:32] + bytes.fromhex(k["ciphertext"])).hexdigest()
    if mac != k["mac"]:
        return None
    # MAC matched, decrypt
    cipher = AES.new(derived[0:16], AES.MODE_CTR,
                     initial_value=bytes.fromhex(k["cipherparams"]["iv"]),
                     nonce=b"")
    return cipher.decrypt(bytes.fromhex(k["ciphertext"]))  # 32-byte private key

The important detail: the MAC is Keccak-256 of derived[16:32] || ciphertext. This lets an attacker skip AES decryption on every wrong guess — but the Scrypt step still costs 256 MB and ~200 ms per try.

Extracting the hash for hashcat

$ python3 ethereum2john.py UTC--2018-07-01T14-42-25.123Z--abc.json > eth.hash
$ cat eth.hash
$ethereum$s*262144*8*1*ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd*5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46*517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2

$ hashcat -m 15700 -a 0 eth.hash wordlist.txt -r OneRuleToRuleThemAll.rule

Real GPU speeds

GPUMode 15700 (Scrypt N=262144)Mode 15600 (PBKDF2)Guesses/day
RTX 4090~4–5 H/s~380 k H/s~430,000 (Scrypt)
RTX 3090~3 H/s~250 k H/s~260,000
CMP 90HX~1.8 H/s~180 k H/s~155,000
CPU (i7-12700K)~30 H/s (all cores)~8 k H/s~2.6 M

Yes, CPU is faster than GPU for Scrypt at N=262144 — the memory bandwidth wins. A modern desktop CPU can out-perform an RTX 4090 by 6×. A 10-CPU cluster beats a 10-GPU cluster. This is by design.

What this means for recovery feasibility

430,000 guesses/day (1 GPU)

A dictionary of 14 M common passwords × 50 rules = 700 M variants. Exhausting this takes ~4.5 years on one GPU, ~2 months on 30 GPUs. A well-tuned rule set + hints finishes in hours for realistic cases.

Sweet spot

Under 50 M candidate variants is recoverable within a day on a small farm. That means: a focused custom dictionary + tight masks — not rockyou + dive.rule.

MetaMask vault — much faster

MetaMask stores its encrypted seed in browser LocalStorage under data. The payload is a JSON blob using PBKDF2-HMAC-SHA256 with 10,000 iterations — much weaker than keystore Scrypt.

{
  "data": "base64...",       // AES-GCM ciphertext
  "iv": "base64...",
  "salt": "base64...",
  "keyMetadata": {
    "algorithm": "PBKDF2",
    "params": { "iterations": 10000 }
  }
}

Hashcat mode 26600 handles MetaMask vaults at ~500,000 H/s on an RTX 4090 — roughly 100,000× faster than Ethereum keystore. Recovery of a typical MetaMask password (8–10 chars, word + numbers) is usually done in under an hour.

Realistic recovery workflow

  1. Identify the Scrypt N value. N=1024 (Parity light wallet) cracks 256× faster than N=262144.
  2. Build a personal dictionary from password manager exports, old text files, browser autofill dumps — not generic wordlists.
  3. Short rule set first. best64.rule (77 rules) before dive.rule (99,092 rules). One-shot tests of "did I use this exact word" are cheap.
  4. Masks for structure. "I always use Word + 4 digits" = ?u?l?l?l?l?l?l?d?d?d?d.
  5. PRINCE for multi-word passphrases — expensive but the only feasible attack on "my dog's name plus my birth year" patterns.

Frequently asked questions

What hashcat mode is used for Ethereum keystore?

Mode 15700 for Scrypt-based v3 keystores (most common). Mode 15600 for the legacy PBKDF2 variant (older MyEtherWallet exports).

Why is Ethereum keystore so slow to crack?

Scrypt N=262144, r=8 requires 256 MB of working memory and ~200 ms of compute per guess — GPU parallelism collapses. A 4090 manages ~4 H/s, not 4 billion.

Can MetaMask vault passwords be recovered?

Yes — MetaMask uses PBKDF2 with only 10,000 iterations. Hashcat mode 26600 runs at ~500,000 H/s on a 4090. Weak passwords fall in minutes.

How is keystore.json different from wallet.dat?

wallet.dat uses SHA-512 iterations (~100 k) — ~55–100 k H/s on GPU. Keystore uses Scrypt — ~4 H/s. Roughly 15,000× harder per guess.

Can I reduce Scrypt parameters to speed up cracking?

No. N/r/p are stored in the keystore and used during verification. Change them and the derived key will not match. Older wallets that shipped with N=1024 are naturally faster.

Submit your keystore for recovery

Because Scrypt is so slow, a tuned attack on a 10-GPU farm is usually the only realistic option for consumers. Pay only on success.