Dockerized Tor Onion Services with Vanity v3 Tor Addresses

I'm currently taking Prof. Florian Tschorch's Network Security class and we had a lecture covering Tor and Onion services. A couple of years ago, I operated a relay node and a Zerobin onion service while taking part in the EFF's Tor challenge.
After the lecture, I feeled like I could bring this pastebin service back online and so I did using docker and a vanity v3 address.

Tor v3 Vanity Addresses

The Tor Rendezvous Specification v3 specifies a new address format. Instead of the quite short v2 Tor addresses which were based on RSA, the new v3 format will have 56 characters and ed25519 elliptic curve keys.

After a bit of googling, I found a tool called mkp224o which helps to generate tor addresses with a specific prefix. As the addresses use Base-32 encoding, you are limited to any characters from upper-case letters A–Z, and the digits 2–7. The tool is pretty straight forward to setup:

$> git clone https://github.com/cathugger/mkp224o.git
$> cd mkp224o
$> ./autogen.sh
$> apt-get install libsodium-dev
$> ./configure
$> make

You'll then end up with a binary called mkp224o and the following options:

$> ./mkp224o --help
Usage: ./mkp224o filter [filter...] [options]
       ./mkp224o -f filterfile [options]
Options:
        -h  - print help to stdout and quit
        -f  - specify filter file which contains filters separated by newlines
        -D  - deduplicate filters
        -q  - do not print diagnostic output to stderr
        -x  - do not print onion names
        -v  - print more diagnostic data
        -o filename  - output onion names to specified file (append)
        -O filename  - output onion names to specified file (overwrite)
        -F  - include directory names in onion names output
        -d dirname  - output directory
        -t numthreads  - specify number of threads to utilise (default - CPU core count or 1)
        -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
        -B  - use batching key generation method (>10x faster than -z, experimental)
        -s  - print statistics each 10 seconds
        -S t  - print statistics every specified ammount of seconds
        -T  - do not reset statistics counters when printing
        -y  - output generated keys in YAML format instead of dumping them to filesystem
        -Y [filename [host.onion]]  - parse YAML encoded input and extract key(s) to filesystem

The README states that reading the OPTIMISATION.txt is recommended and indeed, after passing --enable-amd64-64-24k --enable-intfilter to ./configure, I saw a 2x performance improvement. Furthermore, -B held its promise of another 10x performance boost.

My goal was to create a pastebin onion service, so I wanted to find a tor v3 addresses that begins with torpaste:

$> ./mkp224o -S 5 -d /tmp/torpaste -B torpaste
set workdir: /tmp/torpaste/
sorting filters... done.
filters:
        torpaste
in total, 1 filter
using 6 threads
>calc/sec:17070248.553354, succ/sec:0.000000, rest/sec:59.964621, elapsed:0.100059sec
>calc/sec:16750846.024957, succ/sec:0.000000, rest/sec:0.000000, elapsed:5.103162sec
>calc/sec:16766072.252707, succ/sec:0.000000, rest/sec:0.000000, elapsed:10.106241sec
[...]

The VM was assigned 6 cores and the tool managed to squeeze more than 16M guesses/second out of them. A day later I checked the directory and found several results:

$> ls  torpaste-onions/
torpaste7auh4efyzf6aznwwq7pyvjk2psogj6hmhryjxu7qzbdjglyd.onion  torpastewlv6qw2v77bufvqtq5v4ye2gg6aoaskw2eak7t4bwq237lid.onion
torpastekwlzg35gblm33m3bwotz5blsd2gexz6vbx37is5wl24d5rid.onion  torpastez3lsfwspj7wmlso22trapwjzynlwg2ri4kho6yn57xlcgpad.onion

Within each result directory, there are three files that we will need later when configuring the hidden service:

$> ls torpaste-onions/torpastez3lsfwspj7wmlso22trapwjzynlwg2ri4kho6yn57xlcgpad.onion
hostname  hs_ed25519_public_key  hs_ed25519_secret_key

Keep in mind that depending on the length of the prefix, your personal luck and computing power, it might take several days, months of even years to find a matching address. For example, after more than 3000 CPU-hours with more than 18M guesses/sec, I still have not found an address for thetorbin :-/

Dockerizing a Tor Onion Service

Now that I had my vanity addresses and a matching ed25519 keypair, the only thing left for me to do was to configure tor to serve some content under that address.

I'm not a docker-fanboy, but I wanted to give it a try and run the pastebin and the tor daemon as two docker containers. You can find the docker-tor-pastebin repository on GitHub.

Here's brief summary:

Tor container

The first container sets up Tor with a minimal configuration (torrc), that:

  • Does not start a SOCKS proxy listener
  • Does not act as an Exit node
  • Does not act as an Relay node (feel free to change this)
  • Configures a v3 hidden service
  • Points port 80/tcp of the hidden service to the privatebin container

This is basically everything that we need to run a hidden service, but feel free to read through the code and make adjustments if you need a slightly different configuration.

Although docker exists as a package for Debian, the latest version at the time of writing did not support v3 hidden services. That's why I had to modify the Dockerfile a bit to install the latest version using the recommended way.

The only thing we have to do is to move the contents of the torpaste...-directory into the data/tor/web/ directory, because tor needs to read the public, private and hostname files to start the hidden service.

Pastebin container

The pastebin functionality is powered by the PrivateBin project, because there's a privatebin/nginx-fpm-alpine:latest docker image available that we can easily integrate into our setup.
We simply add it to our docker-compose.yml and link both containers together.

To bring everything to life, we only have to run docker-compose up -d in the folder and then the magic should do its work.

After we allowed tor to build all necessary circuits, we can start browsing to our newly created hidden service with the tor browser:

Tor browser

I'll let this pastebin hidden service up and running as long as my server runs and I have the spare resources for it. Feel free to use it and distribute its existence within the hidden service community :-)

-=-