The mkp224o repository on cathugger’s GitHub account.
Tor Proposal 224 is the proposal for the new Onion v3 specification, so that’s what mkp224o was named after.
mkp224o is very easy to install and run. Download and extract the latest version from GitHub, then on Debian-based systems, you can use:
#Install dependencies if required sudo apt-get install autoconf libsodium-dev #Build ./autogen ./configure make
You can run “./mkp224o -h” to view the available options:
[email protected]:~/onionv3/mkp224o$ ./mkp224o Usage: ./mkp224o filter [filter...] [options] ./mkp224o -f filterfile [options] Options: -h - print help -f - instead of specifying filter(s) via commandline, specify filter file which contains filters separated by newlines -q - do not print diagnostic output to stderr -x - do not print onion names -o filename - output onion names to specified file -F - include directory names in onion names output -d dirname - output directory -t numthreads - specify number of threads (default - auto) -j numthreads - same as -t -n numkeys - specify number of keys (default - 0 - unlimited) -N numwords - specify number of words per key (default - 1) -z - use faster key generation method. this is now default -Z - use slower key generation method -s - print statistics each 10 seconds -S t - print statistics every specified amount of seconds -T - do not reset statistics counters when printing
You can then run mkp224o to search for an address. The “-S” argument will make mkp224o output statistics every 5 seconds, and the “-d” argument allows you to specify a directory to store the generated keys.
[email protected]:~/onionv3/mkp224o$ ./mkp224o -S 5 -d onions jamie set workdir: onions/ sorting filters... done. filters: jamie in total, 1 filter using 4 threads >calc/sec:17035.009192, succ/sec:0.000000, rest/sec:39.964831, elapsed:0.100088sec >calc/sec:22250.236672, succ/sec:0.000000, rest/sec:0.000000, elapsed:5.103855sec >calc/sec:22272.487630, succ/sec:0.000000, rest/sec:0.000000, elapsed:10.107517sec >calc/sec:22256.077578, succ/sec:0.000000, rest/sec:0.000000, elapsed:15.111813sec >calc/sec:22278.089855, succ/sec:0.000000, rest/sec:0.000000, elapsed:20.116102sec >calc/sec:22253.435622, succ/sec:0.000000, rest/sec:0.000000, elapsed:25.120363sec >calc/sec:21762.771552, succ/sec:0.000000, rest/sec:0.000000, elapsed:30.142012sec >calc/sec:22258.870726, succ/sec:0.000000, rest/sec:0.000000, elapsed:35.146309sec >calc/sec:22282.575137, succ/sec:0.000000, rest/sec:0.000000, elapsed:40.150578sec >calc/sec:22258.577166, succ/sec:0.000000, rest/sec:0.000000, elapsed:45.154941sec >calc/sec:22198.079226, succ/sec:0.000000, rest/sec:0.000000, elapsed:50.159383sec >calc/sec:22253.661568, succ/sec:0.000000, rest/sec:0.000000, elapsed:55.163728sec >calc/sec:22276.712822, succ/sec:0.000000, rest/sec:0.000000, elapsed:60.168057sec >calc/sec:22254.261335, succ/sec:0.000000, rest/sec:0.000000, elapsed:65.172357sec >calc/sec:22277.632325, succ/sec:0.000000, rest/sec:0.000000, elapsed:70.176659sec >calc/sec:22256.428313, succ/sec:0.000000, rest/sec:0.000000, elapsed:75.180966sec ^Cwaiting for threads to finish... done.
In the example above, I exited mkp224o after 75 seconds using Ctrl+C.
Matching addresses are automatically saved into either the directory where mkp224o is running or the one specified using the “-d” switch.
[email protected]:~/onionv3/mkp224o$ ls onions/ | head -n 5 jamie22ezawwi5r3o7lrgsno43jj7vq5en74czuw6wfmjzkhjjryxnid.onion jamie22jd4c7g7osiio7jnqnsqj4w7dpqmit32easwp2igjge67nktid.onion jamie233pm4t6zkbkdyiu7yknnqccirtkcwne2h5nc73mykvckg76sqd.onion jamie23kp7n6xgk3lvy6wnse4cuk4dawfpwl52img7za35tiyex2mvyd.onion jamie24hjpe7ia2usa6odvoi3s77j4uegeytk7c3syfyve2t33curbyd.onion [email protected]:~/onionv3/mkp224o$ ls jamie22ezawwi5r3o7lrgsno43jj7vq5en74czuw6wfmjzkhjjryxnid.onion/ hostname hs_ed25519_public_key hs_ed25519_secret_key
You could also set up a cronjob to run mkp224o at boot in a detached screen session:
@reboot cd /path/to/mkp224o && screen -dmS onionv3 ./mkp224o -S 600 -d onions jamie
You can then check up on mkp224o using “screen -r onionv3”. Use Ctrl+A followed by Ctrl+D to detach from a screen session without terminating it.
Running on a Raspberry Pi 2B, mkp224o achieved a pretty consistent 22,200 calculations per second, with 1 filter running on 4 threads.
The 4 Raspberry Pi Zeros all achieved around 4,180 calculations per second, with 1 filter running on 1 thread.
mkp224o ran 24 hours a day for 21 days. The total number of addresses generated by each device is shown below:
Master (RPi 2B) : 1014 Node 1 (RPi Zero) : 222 Node 2 (RPi Zero) : 192 Node 3 (RPi Zero) : 212 Node 4 (RPi Zero) : 235
This makes for a total of 1,875 addresses, which is roughly 1 matching address found every 16 minutes and 8 seconds, or 967.68 seconds.
Address Generation Times
In order to get a very rough estimate for the address generation time for each vanity length, I used the total generation time for the 1,875 addresses that I generated over 21 days, and extrapolated that using the total number of possible characters (32, a-z, 2-7) in order to get values for other vanity address lengths.
These values are estimated using combined data from mkp224o running on 1 Raspberry Pi 2B and 4 Raspberry Pi Zeros, simultaneously and 24/7 for 21 days.
Vanity Characters : Approximate Generation Time 1 : <1 second 2 : <1 second 3 : 1 second 4 : 30 seconds 5 : 16 minutes 6 : 8.5 hours 7 : 11.5 days 8 : 1 year 9 : 32 years 10 : 1,024 years 11 : 32,768 years 12 : 1 million years 13 : 32 million years 14 : 1 billion years 15 : 32 billion years 16 : 1 trillion years 17 : 32 trillion years 18 : 1 quadrillion years 19 : 32 quadrillion years 20 : 1 quintillion years 21 : 32 quintillion years 22 : 1 sextillion years 23 : 32 sextillion years 24 : 1 septillion years 25 : 32 septillion years 26 : 1 octillion years 27 : 32 octillion years 28 : 1 nonillion years 29 : 32 nonillion years 30 : 1 decillion years 31 : 32 decillion years 32 : 1 undecillion years 33 : 32 undecillion years 34 : 1 duodecillion years 35 : 32 duodecillion years 36 : 1 tredecillion years 37 : 32 tredecillion years 38 : 1 quattuordecillion years 39 : 32 quattuordecillion years 40 : 1 quindecillion years 41 : 32 quindecillion years 42 : 1 sexdecillion years 43 : 32 sexdecillion years 44 : 1 septendecillion years 45 : 32 septendecillion years 46 : 1 octodecillion years 47 : 32 octodecillion years 48 : 1 novemdecillion years 49 : 32 novemdecillion years 50 : 1 vigintillion years 51 : 32 vigintillion years 52 : 10^66 years 53 : 10^69 years 54 : 10^72 years 55 : 10^75 years 56 : 10^78 years (1,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000)
A copy of this is available on my Pastebin if you wish to view it without scrolling: https://pastebin.com/hdB8QU6z
I think that 11 vanity characters is realistically achievable given enough computing power, for example when/if Facebook upgrade their hidden service to Onion v3. The Raspberry Pi cluster that I used is a very low performance device when compared to a dedicated GPU crypto rig.
Filtering Generated Addresses
After I had been running mkp224o for 21 days, I needed to use the cluster for something else so it was time to choose an address. Glancing through the results, there wasn’t anything that stood out, so I searched through it with grep for various keywords and acronyms (eg: sec, pgp, php, etc), however there wasn’t anything particularly good.
I wanted to search for English words in the output, so I used the /usr/share/dict/british-english file that is included with the package “wbritish” on Debian-based systems.
At first I tried the following, but it turned out to be extremely inefficient and could cause a system crash, so I do not recommend trying this yourself!
#Install wbritish if required sudo apt-get install wbritish #Make a copy of the british-english dictionary for searching cp /usr/share/dict/british-english wordlist.txt #Remove one character words grep -v "^[A-Za-z]$" wordlist.txt > wordlist2.txt #Remove two character words grep -v "^[A-Za-z][A-Za-z]$" wordlist2.txt > wordlist.txt #Remove "onion", "Onion", "Jamie", "ion", "Jami", "jam" & "Amie" egrep -v "(^onion$|^Onion$|^ion$|^Jamie$|^Amie$|^Jami$|^jam$)" wordlist.txt > wordlist2.txt #Find words from wordlist2.txt in onion-v3-export.txt This could crash your system, be careful! grep -iFf wordlist2.txt onion-v3-export.txt
The reason that this technique is so inefficient is that it uses just one instance of grep for the entire search, and grep isn’t designed to handle that. I had this running for around 5 minutes and it slowly built up 16 GB RAM usage and started eating into my swap partition, which isn’t good! Grep isn’t designed for handling this sort of processing, so it’s unfair to discount it for this memory-handling behaviour.
The technique that worked well was using a separate instance of grep for each word to search for, instead of trying to search for them all at once. This was a slower searching method, however it uses minimal memory.
I also decided to cut the addresses to search down to just the first 12 characters, as words that aren’t at the start of the address aren’t of much value in most cases.
cut -c 1-12 onion-v3-export.txt > onion-cut.txt
Then use a simple bash for loop in order to check each of the dictionary words against the address list individually:
for word in `cat wordlist2.txt`; do grep --colour=always -i "$word" onion-cut.txt; done
I set this running on a Raspberry Pi 2B and it took around 5 hours to search 1875 addresses for around 90,000 dictionary words.
The output can be seen below:
jamieiabe7a4 jamie6r6zala jamiearkjlxm jamiecq7kaug jamiefzubmwi jamieshbikol jamieyvh7chi jamielwsclem jamied4coltx jamied4coltx jamieigdelcr jamie35cjdoe jamieolrdowa jamieastrwc5 jamiecojx25o ...
On a side note, in order to generate HTML output of the ANSI-encoded terminal emulator colours, you can use the “aha” command:
for word in `cat wordlist4.txt`; do grep --colour=always -i "$word" onion-cut.txt; done | aha
…which will convert the input into HTML with inline colour styling and the following header:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <!-- This file was created with the aha Ansi HTML Adapter. https://github.com/theZiz/aha --> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="application/xml+xhtml; charset=UTF-8" /> <title>stdin</title> </head> <body> ...
I then edited out the inline styling and used my CSS file instead in order to be compliant with my Content-Security-Policy.
A significantly better way of filtering the vanity addresses would have been putting them all into a database and querying it, as database software is highly optimised for handling this sort of computation.
I was really hoping to get a ^jamieweb address to go along with my Onion v2 service jamiewebgbelqfno.onion, however with Onion v3 and mkp224o, my estimates show that would take around a year. With Onion v2 and Shallot, that would (and did) take around 25 days.
jamie4debrkhllykiyiztbpg6fokecmzhxvj4buig5qss5m4wasn5yyd.onion - Debian? jamiedgraphfwrf2mfhc4iprjjpgzapiqikjxz4yseodq2bvnqcicoad.onion - Fast Graph Database? jamiedigjmx56qpxfwht6pniy2jibt6lpled4juja3wmyuk7bfeaczad.onion - DNS Lookup Utility? jamieoslok3jxyg223xdm2fftsdd33cio2p5hozkipj27wcygomy4yid.onion - Capital of Norway? jamietap7o7pux6fxpnxrbqvto6dypr3tx3befc7bpon6gn5m4tsftqd.onion - Network Tap?
The full list of generated addresses is available on my Pastebin: https://pastebin.com/eiFYaCHG
As of writing this, Onion v3 support is only available alpha versions of Tor, however a Tor build with Onion v3 functionality is currently at the second release candidate, so it should be reaching the stable branch very soon.
For as long as Tor Onion v3 functionality remains in alpha only, I will be keeping the current hidden service address (http://32zzibxmqi2ybxpqyggwwuwz7a3lbvtzoloti7cxoevyvijexvgsfeid.onion) as well as running the Tor alpha instance on a separate, isolated server.
When Onion v3 hits Tor stable, I will move it across to a main server as well as start using the jamie3vkiwi vanity address. I will also continue hosting my Onion v2 hidden service for as long as it is safe to do so.
Luckily it is very easy to host multiple hidden services using the same Tor instance. In your torrc, just add multiple hidden service configurations:
HiddenServiceDir /desired/path/to/v3/hidden/service/config HiddenServiceVersion 3 HiddenServicePort <localport> <server> HiddenServiceDir /desired/path/to/v2/hidden/service/config HiddenServiceVersion 2 HiddenServicePort <localport> <server>
Other Onion v3 Vanity Address Generation Programs
- horse25519: https://github.com/Yawning/horse25519
- oniongen-go: https://github.com/rdkr/oniongen-go
- oniongen-c: https://github.com/rdkr/oniongen-c
I personally tried out oniongen-go and oniongen-c in addition to mkp224o.
If I have missed any, please let me know.
To conclude, I think that mkp224o is fantastic software that worked stably for prolonged amounts of time on low-end hardware. If you want to generate a vanity address for your own Onion v3 service, definitely check out mkp224o.
I am definitely not as happy with my Onion v3 vanity address as I am with my Onion v2 vanity address, however due to the enormously increased cryptographic security of Onion v3, vanity address generation takes slightly longer. This is not a problem for me though, since security is always more important that vanity, especially with software like Tor.