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 Scallion

Scallion is one tool that can be used for generation. Unlike previous tools for generation addresses, Scallion focuses on GPUs, meaning it works much faster than CPU-targeting utilities in most cases. In my experience, Scallion does not work on ARM devices (Use Shallot or Eschalot instead), but if you have an x86_64 processor and some sort of video graphics (integrated or otherwise), you should be good to go.

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 some dependencies and then clone Scallion onto your machine:

$ sudo apt install clinfo mono-complete mono-devel nvidia-opencl-common nvidia-opencl-dev nvidia-opencl-icd libssl1.0-dev beignet beignet-dev ocl-icd-opencl-dev ocl-icd-libopencl1
$ git clone https://github.com/lachesis/scallion.git

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

$ cd scallion
$ xbuild scallion.sln /p:TargetFrameworkVersion="v4.5"

Next, we will get a list of all of the devices that can be used for generating addresses:

$ mono scallion/bin/Debug/scallion.exe -l
Id:0 Name:Intel(R) HD Graphics Skylake Desktop GT2
    PreferredGroupSizeMultiple:16 ComputeUnits:24 ClockFrequency:1000
    MaxConstantBufferSize:134217728 MaxConstantArgs:8 MaxMemAllocSize:3221225472

We can see I have one device with an identifier that I can target. You may have more than one device.

Now we can use Scallion to find an address that starts with a word or phrase of our choice. Let’s start Scallion with 8 threads, and have it use device ``. 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:

$ mono scallion/bin/Debug/scallion.exe -t8 -d 0 apple
Cooking up some delicious scallions...
Using kernel optimized from file kernel.cl (Optimized4)
Using work group size 16
Compiling kernel... done.
Testing SHA1 hash...
CPU SHA-1: d3486ae9136e7856bc42212385ea797094475802
GPU SHA-1: d3486ae9136e7856bc42212385ea797094475802
Looks good!
LoopIteration:1  HashCount:16.78MH  Speed:98.7MH/s  Runtime:00:00:00  Predicted:00:00:00  Found new key! Found 1 unique keys.

  2018-01-03T00:24:24.645322Z
  applencoaipu4tqj.onion
  -----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCcDTg3+pON2oUclpStVlFVhtcpleNwtmdO3ZVuN2cPe9tyATjH
fye++edUSTwVm6EZZABrK3iSBdGAITXxRpc5dBM+SHPals6DEECRffa+d2QazJq2
xjhU7sfocXMzly+lALtE3T/I8yhFwcDlv/LGsWn6P9Hh2A2otDz3SCeGCQIEXGYD
DwKBgBkW9kDgDFafPvLhA0YIaDei5tBR5gJXt2vqabJfbi8P7RKF3GJ6vlHXu7xS
XikDmN5lJ+dAeFH5mH4mx0TAyfpjHvwrvCcVFPuXnt8ufDHYnRc5B8hYg/bpe0eS
9iZpSFKvq1Io49Wlt04KKAW86Nk0EJRPlkU6ewfOvs5AHI9vAkEAz+N847csHbcx
79RlBhvoT+GUYoSdKvtB+0pyv4mRYEV3SHFATVwXlTksOcPkI1dFVftkoXaEEld2
RTmsVlaLNQJBAMAqnKx+s4LAj2NxzBTpbcpeVY+DauWBoNMUo5Qdqm3SSV4hPsbd
Bf99XvCWS+7tD+jhks4mffOcKQZNK4JHVgUCQQDH6n4Uf2QWhZHvnY0niHE0ydiu
f2KIBc2spzWzcCWiyBqmtAbjhT3/HajJHB3zYdzHPrI0uVFHVqrjBnhRKSVjAkEA
vWUSQ9u4jPBH/z3ahdD6kbvQA90Jxo/JQgrwaHAUrli/SvmOC3xx/kSWLVPSlSk4
p96zeIgMolOS4Tfiff+newJAUaCQumLZori7RCT+2XOXFCoV03TLlujS8L+2sNH1
LPR8Brc3CBv+ZlleYnJCR4J88py8dFGYSYM95qmpCek1SA==
-----END RSA PRIVATE KEY-----

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 scallion executable with the --help flag:

$ mono scallion/bin/Debug/scallion.exe --help
Usage: scallion [OPTIONS]+ regex [regex]+
Searches for a tor hidden service address that matches one of the provided regexes.

Options:
  -k, --keysize=VALUE        Specifies keysize for the RSA key
  -n, --nonoptimized         Runs non-optimized kernel
  -l, --listdevices          Lists the devices that can be used.
  -h, -?, --help             Displays command line usage help.
      --gpg                  GPG vanitygen mode.
  -d, --device=VALUE         Specifies the opencl device that should be used.
  -g, --groupsize=VALUE      Specifies the number of threads in a workgroup.
  -w, --worksize=VALUE       Specifies the number of hashes preformed at one
                               time.
  -t, --cputhreads=VALUE     Specifies the number of CPU threads to use when
                               creating work. (EXPERIMENTAL - OpenSSL not
                               thread-safe)
  -p, --save-kernel=VALUE    Saves the generated kernel to this path.
  -o, --output=VALUE         Saves the generated key(s) and address(es) to this
                               path.
      --skip-sha-test        Skip the SHA-1 test at startup.
      --quit-after=VALUE     Quit after this many keys have been found.
      --timestamp=VALUE      Use this value as a timestamp for the RSA key.
  -c, --continue             Continue to search for keys rather than exiting
                               when a key is found.
      --command=VALUE        When a match is found specified external program
                               is called with key passed to stdin.
                               Example: "--command 'tee example.txt'" would
                               save the key to example.txt
                               If the command returns with a non-zero exit code,
                                the program will return the same code.