Creating a BTSync encrypted read-only peer
Oct 18, 2015
Tag: linux
Update (January 23, 2016): encrypted folders are a standard feature since version 2.3 of Bittorrent Sync. As a consequence, you can now get the necessary keys from the user interface.
The problem
BitTorrent Sync is a peer-to-peer folder synchronisation utility. Its day-to-day use is comparable to cloud sync such as Dropbox, Google Drive, or OneDrive, however there is no central party that stores the data and coordinates synchronisation. Since there is no centralized storage and the user can decide who can read a folder, BitTorrent Sync provides more privacy and security.
Since Bittorrent Sync is a peer to peer system, at least one peer needs to be online to syncronize a particular folder. For this reason, many users use a NAS or other always-on machine to have a peer that is always visible. (E.g., we use a Raspberry Pi 2 as an always-on peer.)
Unfortunately, most residential internet connections have limited upstream bandwidth. Consequently, synchronizing with your always-on peer can be slow outside the confines of your home (or business) network. The obvious solution to this problem is to use a VPS or dedicated server in a well-connected data center as a (read-only) peer. However, this brings back some of the downsides of cloud-based solutions: if your peer is hacked or seized, a third party has access to all your synchronized data.
Shared keys
Luckily, Bittorrent Sync has an elegant solution, known as a encrypted read-only peer. Unfortunately, this feature is not advertised outside their key structure spec. To understand how this feature works, we will first do a quick run-down of how folders are shared in Bittorrent Sync. As of Bittorrent Sync 2.0, there are two types of folders:
- Standard folders: rely on a shared key mechanism to discover and obtain access to a folder.
- Advanced folders: rely on user identity to discover and obtain access to a folder.
Although the newer advanced folders offer more flexibility (such as changing access rights), only standard folders currently provide a solution to the `vulnerable cloud peer’ problem. To understand how this works, we have to dissect the mechanics of standard folders a bit. Normally, there are two types of keys: a read-write key and a read-only key. The read-write key starts with an A, followed by 160 bits of random material encoded in Base32. For example:
AKBI7V5S7ANHJTZ2VJ66M5KEAHLFQPYEP
Sync derives a couple of things (in)directly from this key:
- A asymmetric keypair (ED25519) that is used for signing (and verifying) changes to a folder. Peers only accept changes that are correctly signed. cannot sign modification requests.
- The read-only key is derived from the public key. Like the read-write key, this key contains 160-bits of material and starts with a B. The read-only key can be used to connect to and sync with other peers. However, since read-only peers do not have access to the signing key, they cannot sign modification requests.
- The folder ID is derived from the read-only key. This ID is used to discover peers that have a particular folder on the local network, tracker or DHT.
Unfortunately, the spec is not completely clear on how the read-only and folder IDs are derived. I could not quickly reproduce the keys in most of the obvious ways (e.g. expanding the secret to 256 bit using SHA3 and generating the ED25519 keypair using that material). The mechanism has definitely changed since it was last reverse engineered.
The solution
Bittorrent Sync knows another type of read-write key that is described in the key structure spec. This key also consists of 160-bits of random material, but is prefixed by a D rather than A. The GUI does not provide an option to generate such a key. Luckily, it is easy to do so in a UNIX with some Python:
$ dd if=/dev/urandom bs=20 count=1 | \
/usr/bin/python -c "import sys;import base64; sys.stdout.write(base64.b32encode(sys.stdin.read()))" | \
sed 's/^/D/'
The change of A to D causes Bittorrent Sync to generate a read-only key twice the size (prefixed by E). The key now contains separate secrets for connecting to other peers and data encryption. Additionally, an encrypted read-only secret is created. This consists of the initial half of the read-only key and uses the prefix F. Peers that have this encrypted read-only secret can connect to and sync with other peers. However, they cannot decrypt the data, since they do not have the encryption key.
So, in our cloud scenario, this provides an elegant solution:
- Use a read-write or read-only key for trusted peers.
- Use a encrypted read-only key for untrusted cloud peers.
Luckily, the UI is pretty nice once you have generated a secret starting with D. Under the folder preferences, you can see all keys:
Setting up a cloud peer
Setting up a Bittorrent Sync on a VPS is pretty easy. I won’t provide a copy-paste guide to set up a VPS, because security. But assuming that you set up a VPS with systemd (I use Debian stable on Scaleway) and have Bittorrent Sync installed in /opt/btsync, you can use the configuration below. The use of systemd gives us two advantages over e.g. System V init: (1) Bittorrent Sync can be restarted automatically if it crashes and (2) setting up instances for multiple users is easy.
Per-user configuration
Assuming that you have a user alex, create the directories .sync, btsync, btsync-aux:
$ mkdir .sync btsync btsync-aux
Create a self-signed keypair that will be used by the Bittorrent Sync web UI:
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout .sync/sync.key -out .sync/sync.crt
Then create a file .sync/sync.conf with the following content:
{
"storage_path" : "/home/alex/btsync-aux",
"display_new_version": false,
"disk_low_priority" : true,
"lan_encrypt_data" : true,
"rate_limit_local_peers" : false,
"folder_rescan_interval" : 600,
"folder_defaults.delete_to_trash" : true,
"folder_defaults.use_lan_broadcast" : true,
"folder_defaults.use_relay" : true,
"folder_defaults.use_tracker" : true,
"sync_trash_ttl" : 365,
"folder_defaults.known_hosts" : "",
"use_upnp" : false,
"webui" :
{
"directory_root" : "/home/alex/btsync",
"listen" : "127.0.0.1:8888",
"force_https" : true,
"ssl_certificate" : "/home/alex/.sync/sync.crt",
"ssl_private_key" : "/home/alex/.sync/sync.key"
}
}
If multiple users will have an instance on that host, you should give them unique port numbers. You can use the same setup for each Bittorrent Sync user.
You can check if the configuration works by starting Bittorrent Sync (as alex):
$ /opt/btsync/btsync --nodaemon --config /home/alex/.sync/sync.conf
You can stop Bittorrent Sync by sending a SIGINT signal (Ctrl-C)
systemd unit
Next, we will have to create a systemd unit file which can be used to control the lifecycle. We will use a unit file ending with @, so that we can start instances per user. Create the file /etc/systemd/system/btsync@.service with the following contents:
[Unit]
Description=BitTorrent Sync for %i
[Service]
Type=simple
User=%i
ExecStart=/opt/btsync/btsync --nodaemon --config /home/%i/.sync/sync.conf
WorkingDirectory=/home/%i
Restart=always
[Install]
WantedBy=multi-user.target
The configuration is pretty simple: the btsync command is invoked as before, though we are using variables in to set the correct username. Moreover, the Restart policy is set to always so that btsync will be restarted when it exits.
You can now start/stop/restart the Bittorrent Sync instance for the user alex with:
$ sudo systemctl start btsync@alex.service
$ sudo systemctl stop btsync@alex.service
$ sudo systemctl restart btsync@alex.service
If you want to start the instance automatically during boot:
$ sudo systemctl enable btsync@daniel.service
Accessing the web interface
To add folders using read-only encrypted secrets, use the web interface (click the gear, and then Manual connection). Although the web interface is protected using a user/password combination set up during the first use, you probably do not want to expose it to the net. For this reason, the configuration above binds it to localhost. To access the web interface on http://localhost:8888, set up an SSH tunnel to your VPS:
$ ssh -L 8888:localhost:8888 <your-VPS>
Also, if you are using the Pro of Bittorrent Sync version locally, create a new identity for the cloud peer (otherwise, it would get access to any read-write or read-only secrets that you use).
Note: To avoid that Sync needs relay servers, look up the port in the preferences, and ensure that it is not blocked by your firewall.