Generate a Chrome extension ID with a chosen substring by brute‑forcing RSA keys.
$ crx-vanity hiii
Mining "hiii" with 8 workers...
Target length 4 | match Start | positions 1
Expected attempts (mean) ≈ 16^4 / 1 = 65536
3363 attempts... (3279/s) [#-------------------] 5.1% of expected | p(hit) 5.0% | ETA to 95% 59s
6739 attempts... (3263/s) [##------------------] 10.3% of expected | p(hit) 9.8% | ETA to 95% 58s
10166 attempts... (3283/s) [###-----------------] 15.5% of expected | p(hit) 14.4% | ETA to 95% 57s
13544 attempts... (3285/s) [####----------------] 20.7% of expected | p(hit) 18.7% | ETA to 95% 56s
16963 attempts... (3298/s) [#####---------------] 25.9% of expected | p(hit) 22.8% | ETA to 95% 54s
20380 attempts... (3300/s) [######--------------] 31.1% of expected | p(hit) 26.7% | ETA to 95% 53s
23800 attempts... (3307/s) [#######-------------] 36.3% of expected | p(hit) 30.5% | ETA to 95% 52s
27102 attempts... (3294/s) [########------------] 41.4% of expected | p(hit) 33.9% | ETA to 95% 51s
30464 attempts... (3294/s) [#########-----------] 46.5% of expected | p(hit) 37.2% | ETA to 95% 50s
33818 attempts... (3294/s) [##########----------] 51.6% of expected | p(hit) 40.3% | ETA to 95% 49s
37170 attempts... (3293/s) [###########---------] 56.7% of expected | p(hit) 43.3% | ETA to 95% 48s
40514 attempts... (3292/s) [############--------] 61.8% of expected | p(hit) 46.1% | ETA to 95% 47s
43824 attempts... (3288/s) [#############-------] 66.9% of expected | p(hit) 48.8% | ETA to 95% 46s
Found after 44969 attempts (13.7s)! (69% of expected attempts)
ID: hiiiaankmcecnmpckobffincdkkifbed
PublicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMydIXXwaj2kDIAvmo/s...
PrivateKey: MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAzJ0h...
Chrome extension IDs are derived from the SHA‑256 hash of the public key, mapped to letters a–p (a base‑16 alphabet). That means your target must only use a–p and the ID length is always 32 characters.
Note: This works for unpacked development and self-distributed .crx files. Chrome Web Store assigns its own ID—you can't choose it.
Requires OpenSSL development headers (libssl-dev on Debian/Ubuntu, openssl on macOS via Homebrew).
cargo build --release
crx-vanity <TARGET> [--bits <BITS>] [--position <start|end|any>]
Examples:
# Find a prefix
cargo run -- melon
# Find a suffix
cargo run -- melon --position end
# Find anywhere in the 32-char ID
cargo run -- melon --position any
# Increase key size (slower)
cargo run -- melon --bits 2048
-b, --bits <BITS>: RSA key size in bits (default: 512)-p, --position <start|end|any>: match mode (default:start)-t, --threads <N>: number of worker threads (default: CPU count)--eta-confidence <0..1>: confidence level for ETA (default:0.95)--progress-secs <N>: progress log interval in seconds (default:10)-n, --no-color: disable ANSI color output (also disabled whenNO_COLORis set)
The miner prints progress to stderr and the final result to stdout, so you can pipe stdout safely.
p(hit)is the probability you’ve found a match by the current attempt count.ETA to 95%estimates time to reach that confidence level, based on current average rate.
Expected attempts scale as 16^L where L is the target length (for any, divide by the number of possible positions). For long targets, expected runtimes become extremely large.
Unpacked development: Add to manifest.json for a stable ID across machines:
{
"key": "BASE64_PUBLIC_KEY",
...
}Chrome Web Store: Not applicable—CWS assigns the ID, not your key.
Self-distributed .crx: You need the private key to sign. Convert to PEM:
echo "BASE64_PRIVATE_KEY" | base64 -d | openssl pkey -inform DER -out key.pemKeep this .pem safe—you'll need it for every update.
The default 512-bit keys are fine for extension ID generation—Chrome only uses the key to derive the ID. The private key is used to sign .crx packages and verify updates come from the same publisher. If this matters to you, use --bits 2048 (or 4096 for long-term security).
MIT