Ever wonder how Tor sites get those custom vanity .onion addresses such as silkroada7bc3kld.onion? These addresses can be generated by hidden service operators for production use, and are just as secure as the automatically generated (and often more cryptic) addresses.

Hidden service .onion addresses are really just the public part of a key pair. Utilizing asymmetric encryption, a hidden service uses the public key (a 16 character string that functions as the actual address prefix) and a private key (a much longer string that is known only to the hidden service) to verify the identity of the service. Anyone connecting to the public key can only do so if the hidden service has access to the private key. Under normal circumstances, only the service operator has access to that private key, so you could trust that the address has not been hijacked.

Keep in mind, while it takes a long time, it is possible for someone to generate the same keypair as another hidden service. While computationally expensive, entities able to throw enough resources at generating an identical address would be able to do so much more quickly than someone acting alone on a sole machine.

Generation with Shallot

Shallot is one tool that can be used for generation. Under the name onionhash, Shallot was first created and maintained by an anonymous developer named Bebop. After Bebop disappeared, development continued with the help of a programmer named `Orum who renamed it Shallot before disappearing himself. Eventually, katmagic moved the code to github where it lives today, but without active development. Over the years, other developers have made fixes, but none of them have been moved into the master branch of the application. Shallot will not be as fast as a tool like Scallion, but it is (in my opinion) more portable as Scallion seems to have issues running on ARM-based SOCs.

Let’s get started generating custom .onion addresses. I will assume that you have access to a Linux machine and are familiar with the terminal.

First, clone Shallot onto your machine:

$ git clone https://github.com/katmagic/Shallot.git

Now, we will move to the Shallot directory, and download and apply some patches:

$ cd Shallot
$ wget https://patch-diff.githubusercontent.com/raw/katmagic/Shallot/pull/9.patch
$ git apply 9.patch
$ wget https://patch-diff.githubusercontent.com/raw/katmagic/Shallot/pull/16.patch
$ git apply 16.patch
$ wget https://patch-diff.githubusercontent.com/raw/katmagic/Shallot/pull/25.patch
$ git apply 25.patch

Wait, what are these for?

  • Patch #9 fixes an off-by-one error that caused generation of incorrect keys.
  • Patch #16 adds an optimization for computing powers of 2 using a bitshift.
  • Patch #25 adds use of memcmp to speed up regular expression use.

Next, we will configure and make to build the shallot executable:

$ ./configure && make

We can now test it by generating an address that starts with “apple” utilizing regular expressions:

$ ./shallot ^apple

After a little waiting, you should get some similar output with the .onion address (public key) and the private key:

$ ./shallot ^apple
-----------------------------------------------------------------
Found matching domain after 9231616 tries: applelmehzgcx37v.onion
-----------------------------------------------------------------
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC1szzknIej9Cn32XEarL1TFJXGOWpllK8NDSLKsJfwBIW3kyFb
F996LeIX7wKomRuudZ8TfyCQsdL4XT27MvZTX/HTjYc1TErpw6s+0n1WXm/+sbgD
/8X1vpt/m4OLZS+JOgDSFNM9zi1Qy2GOAMGlyBA5nXKxo5h60vOA87RVowIEARq5
/wKBgBGN/v/RFriNmAd572mI8SiMK5NBO6yu33wz1kf15Xqh/K6QE9Tsr/htYNjr
/RBb7JgIDCXFl0Bsjfnqtsp/WPe5eWUJkzePpzrIyrgAgFneHYYPeKbhUuEwB20i
mFBKXgZmX2yK6BtJDMAjorq/E/hoe9ecKzGaTrv04LTquiIvAkEA43+W3lXBgUIE
EO9ckIHrQ94DvhCtwQGg1vQFLovbvgBL1rqDgmmrWrUrqjqAJXZj8Iou+k+Z9xkK
fn6O4WfMsQJBAMx2ymXmNI8mldwGcl18LvnYGeTCEy0pD6j2yM5LsBNj9G0ZKcFV
n9gAkG5VumCW3yNvGVao7s9B0cjw63n5jJMCQF1ETnd7YOZb20e6GPWxJ1jlXAG7
CapYtn42LBPD9JgNNw8RqKz+zOPu61kWFXMOQnlruLh127218FVsfbvilt8CQFi7
dTZ0DwIPQRwB5QaGe2ymXFSj1yMbDMh9Z/7TXcmdSnigfDfGykQN27qYPwB8CcTM
MfZszZukdmgYFYx+H8cCQDrGHNbtSePX53ATAf2nP6Wqzi438d4Aegev5qOaTLk6
ol+H4euHzOO7R/YmWcXRWSZAwFfmboNb5xMfR54SK+k=
-----END RSA PRIVATE KEY-----

The private key and address usually sit in files within the /var/lib/tor/hidden_service/ directory and are named hostname and private_key respectively.

For a full list of options and flags, we can run the shallot executable with no arguments:

$ ./shallot
Usage: shallot [-dmopv] [-f ] [-t count] [-x time] [-e limit] pattern
  -d        : Daemonize (requires -f)
  -m        : Monitor mode (incompatible with -f)
  -o        : Optimize RSA key size to improve SHA-1 hashing speed
  -p        : Print 'pattern' help and exit
  -f  : Write output to 
  -t count  : Forces exactly count threads to be spawned
  -x secs   : Sets a limit on the maximum execution time. Has no effect without -m
  -e limit  : Manually define the limit for e

The repository on Github also has a handy chart to estimate how long it will take to generate an address matching a certain number of characters on a 1.5GHz processor:

characters | time to generate (approx.)
-------------------------------------------------------------------    
1          | less than 1 second    
2          | less than 1 second    
3          | less than 1 second   
4          | 2 seconds    
5          | 1 minute    
6          | 30 minutes    
7          | 1 day    
8          | 25 days  
9          | 2.5 years  
10         | 40 years  
11         | 640 years  
12         | 10 millenia  
13         | 160 millenia  
14         | 2.6 million years