06 June 2016

Quick, easy, secure file sharing

I've recently been sent a number of files using transfer.sh by Nathan. You should check this out- in short, you can upload a file (up to 10Gb) to their server, where it will sit for 14 days. You get a link that you can share with your friends, and they can get a direct download from it. I'll discuss in a bit a nice little shell script you can use, or even just add as a one liner to your .bashrc or .zshrc (depending on your preference). Also, I quite like the fact the data only persists for 14 days... this acts like a like a nice little time-out feature, so you don't have to worry about destroying the file once it has been shared. Oh, did I mention it is free?

My problem, though, is that anyone can download the file should they intercept the link to your file. Not great for sharing secure data. This is where GNU Privacy Guard (gpg) comes in to play.

What I will discuss here is asymmetric encryption, involving a private and public key pair. As the names suggest, keep the private one to yourself, and share the public key. The public key can be used to encrypt files, and without the private key, you cannot decrypt them. So you can share your public key as openly as you like- without the private key, it can't be used for anything. In other words, the sender can encrypt using your public key and feel safe in the knowledge that only you can decrypt it, as you (should be) the only person with access to your private key.

In my old job, we used to mess around with crappy open-sourced point-and-click applications that were clunky and would crash all the time if you wanted to encrypt anything larger than a Gb or so. It seems that if you are running on Linux (Ubuntu in my case) you can go straight to the source, and use the awesome gpg utilty via the command line.

So, after a little playing around, here are the steps I took to encrypt and transfer files!

Step 1: Using transfer.sh

Have a look at the instructions provided by the folks behind transfer.sh. The syntax:

curl --progress-bar --upload-file [file] https://transfer.sh

will do the job nicely. To make this even easier for yourself, add a one-liner into your .zshrc- I have a little function that takes the file name as an argument to upload the file.

The file is uploaded, and the download link is displayed on the terminal, so you can copy and paste it into an email or message to send to the recipient. Now, I hear you shout, surely anyone can download the file if they get the link? Why yes, you are correct! So how do we go about encrypting it then, so that only our desired recipient can use the file?

Step 2: Generate a key

Right, now that we can easily share using transfer.sh, lets get down to some encryption. I suggest a quick read of the gpg manual (man gpg) first, and the steps I used are the following:

Start by generating the key with

gpg --gen-key

I followed all the defaults to generate a 2048-bit key, adding my name as the key name, and my email address. My (limited) understanding is that a 4096-bit key isn't significantly more secure than a 2048-bit, so the default is good enough. Finish working through the options, and you will be prompted to create some entropy (I wish my thermodynamics exams were that easy). Once you have generated the key, you can check it with

gpg --list-keys

Step 3: Sharing your public key

Right, that was straightforward so far. Now, we want to export the public key- this can be shared with anyone and everyone. The idea is when you encrypt a file, you select who you want to be able to decrypt it by using their public key. When they recieve the file, they require their private key to perform the decryption.

Your key can be exported using:

gpg --armor --export Philip > phil_public.asc

Here the key is referenced by name 'Philip', and I export it to a file called phil_public.asc- obviously choose the key name and output file sensibly according to your key!

Now this public key can be shared using any means you like (secure or insecure)- email, dropbox, over a network using the netcat utility, etc. It doesnt matter in the slightest if your public key gets compromised- it it utterly useless without your private key.

Once you have your friend's key, import it with

gpg --import nathan_public.asc

where here, Nathan sent me his public key in a file called nathan_public.asc. Once imported, I can check my available keys with

gpg --list-public

and

gpg --list-secret

I should see all my public keys (including the one Nath sent over) using the first command, and my private key using the second.

Step 4: Encrypting a file

Right, now we have keys set up. Encrypting a file is super easy, and if you want to encrypt a directory compress it first using tar or equivalent.

I decided to share a pdf document containing my cheat sheet of shell commands with Nathan. As I'm worried about this top secret information falling into the wrong hands, lets encrypt it using

gpg -e -r Nathan shellcommands.pdf

The -e option instructs gpg to encrypt the file, and -r specifies that I want to use Nathan's public key. That is, Nathan should be able to decrypt this file using his private key. Anyone else might have a bit of a problem reading this document!

Step 5: Sharing the Encrypted File

Now we can share the encrypted file using whatever means we like. I'm going to use transfer.sh - but you could use email, Dropbox, cloud storage etc.

curl --progress-bar --upload-file shellcommands.pdf.gpg https://transfer.sh

I can then share the link produced to allow the recipient to download the file.

Step 6: Decrypting the File

Once Nathan has recieved the file, he can now decrypt it using

gpg -o shellcommands.pdf -d shellcommands.pdf.gpg

The -o option specifies the output file (shellcommands.pdf), and the -d tells gpg to decrypt shellcommands.pdf.gpg

It's that straighforward! Significantly less hassle than other methods I have used in the past.

Other Thoughts

Well that's all for now. I referenced this quite heavily, so go check it out if you want slightly more in-depth detail. This encryption method is great for use with transfer.sh as it means even if the link to the download gets compromised, only the intended recipient can decrypt the file.

I've found it quite interesting getting a little taste of how easy it is to add security to file sharing- this method is essentially unhackable by brute force means, and the only way your files will be compromised is if someone gets hold of your private key (hint: keep it safe, perhaps on an encrypted USB hidden under your bed).

The gpg utility is absolutely fantastic, and can do a wealth of other things, such as sign files (handy if you need a way to verify the authenticity of a file), and I have no doubt barely scratched the surface of its full range of capabilities. Something to investigate in the future, but for the time being I have got the functionalty I require. My final job will be to make a function to place in my .zshrc that takes the file name and the public key(s) as input, and encrypts and uploads in one step.

TL;DR - a quick and convenient way to encrypt and share files, using gpg and transfer.sh