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 Eschalot

Eschalot is one tool that can be used for generation. Eschalot is based off of another tool I previously covered called Shallot. While Shallot only allowed for some basic matching with regular expressions, Eschalot gives the user a bit more control and even supports word lists. Eschalot 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. I will be using Debian, but this guide should be easy to modify for most distributions.

First, install OpenSSL if we don’t have it, then clone Eschalot onto your machine:

$ sudo apt-get install openssl
$ git clone https://github.com/ReclaimYourPrivacy/eschalot.git

Now, we will move to the eschalot directory, and build the eschalot executable:

$ cd eschalot
$ make

We can now make sure everything is working using the builtin testing option:

$ make test
./worgen 8-16 top150adjectives.txt 3-16 top400nouns.txt 3-16 top1000.txt 3-16 > wordlist.txt
Will be producing 8-16 character long word combinations.
Reading 3-16 characters words from top150adjectives.txt.
Reading 3-16 characters words from top400nouns.txt.
Reading 3-16 characters words from top1000.txt.
Loading words from top150adjectives.txt.
Loaded 150 words from top150adjectives.txt.
Loading words from top400nouns.txt.
Loaded 400 words from top400nouns.txt.
Loading words from top1000.txt.
Loaded 974 words from top1000.txt.
Working. 100% complete, 31122412 words (approximately 377Mb) produced.
Final count: 31366539 word combinations.
./eschalot -vct4 -f wordlist.txt >> results.txt
Verbose, continuous, no digits, 4 threads, prefixes 8-16 characters long.
Reading words from wordlist.txt, please wait...
Loaded 31366539 words.
Sorting the word hashes and removing duplicates.
Final word count: 31363570.
Thread #1 started.
Thread #2 started.
Thread #3 started.
Thread #4 started.
Running, collecting performance data...
Found a key for kindland (8) - kindlandudsw7nga.onion
Found a key for loudhour (8) - loudhourvype7cyn.onion
Found a key for cutwaxwin (9) - cutwaxwinstsf6mk.onion
Total hashes: 177519717, running time: 10 seconds, hashes per second: 17751971

When done, simply clean up the test results:

$ make cleantest

Now is a good time to use Eschalot to find an address that starts with a word or phrase of our choice. Let’s start Eschalot in verbose mode, with 4 threads, and have it continue to look for addresses even after it has found one. We will look for addresses that start with “apple”. After a little waiting, you should get some similar output with the .onion address (public key) and the private key:

$ ./eschalot -t4 -v -c -p apple
Verbose, continuous, no digits, 4 threads, prefixes 5-5 characters long.
Thread #1 started.
Thread #2 started.
Thread #3 started.
Thread #4 started.
Running, collecting performance data...
Found a key for apple (5) - appleiujtls4awea.onion

Additionally, you can use the included worgen utility to generate word lists that can be fed into Eschalot. Below is an example series of commands that will generate 10-character strings by mixing nouns that are 3-10 characters long each, and then run the list through Eschalot. Eschalot comes with several different word lists included what can be used by the worgen utility.

$ ./worgen 10-10 nouns.txt 3-10 nouns.txt 3-10 > wordlist.txt
$ ./eschalot -vct4 -l 10-10 -f wordlist.txt > results.txt

After generating a private key and address, you will want to use them with your Tor hidden service. 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 eshalot executable with no arguments:

$ ./eschalot
Version: 1.2.0

eschalot [-c] [-v] [-t count] ([-n] [-l min-max] -f filename) | (-r regex) | (-p prefix)
-v : verbose mode - print extra information to STDERR
-c : continue searching after the hash is found
-t count : number of threads to spawn default is one)
-l min-max : look for prefixes that are from 'min' to 'max' characters long
-n : Allow digits to be part of the prefix (affects wordlist mode only)
-f filename: name of the text file with a list of prefixes
-p prefix : single prefix to look for (1-16 characters long)
-r regex : search for a POSIX-style regular expression

eschalot -cvt4 -l8-12 -f wordlist.txt >> results.txt
eschalot -v -r '^test|^exam'
eschalot -ct5 -p test

base32 alphabet allows letters [a-z] and digits [2-7]
Regex pattern examples:
xxx must contain 'xxx'
^foo must begin with 'foo'
bar$ must end with 'bar'
b[aoeiu]r must have a vowel between 'b' and 'r'
'^ab|^cd' must begin with 'ab' or 'cd'
[a-z]{16} must contain letters only, no digits
^dusk.*dawn$ must begin with 'dusk' and end with 'dawn'
[a-z2-7]{16} any name - will succeed after one iteration

You can also run the worgenexecutable with no arguments for a complete list of options:

$ ./worgen
Version: 1.2.0

usage: worgen min-max filename1 min1-max1 [filename2 min2-max2 [filename3 min3-max3]]
  min-max   : length limits for the output strings
  filename1 : name of the first word list file (required)
  min1-max1 : length limits for the words from the first file
  filename2 : name of the second word list file (optional)
  min2-max2 : length limits for the words from the first file
  filename3 : name of the third word list file (optional)
  min3-max3 : length limits for the words from the first file

  Example: worgen 8-12 wordlist1.txt 5-10 wordlist2.txt 3-5 > results.txt

              Generates word combinations from 8 to 12 characters long
              using 5-10 character long words from 'wordlist1.txt'
              followed by 3-5 character long words from 'wordlist2.txt'.
              Saves the results to 'results.txt'.