Securely Exchange Files over HTTP
Need to exchange sensitive files between two machines but only have readily available operating system tools at your disposal? Here’s how to do it securely via HTTP!
The original version of this article was using the readily available
openssl
command. Just before publication, I stumbled across a StackExchange reply which describes in great detail why using OpenSSL for general purpose encryption is not recommended. After lengthier considerations, I decided to leave theopenssl
commands in but generally promote the more secure and purpose-built GnuPG encryption tools.
TL;DR: Just 8 Steps for the Impatient
If you don’t fancy a step-by-step guide or pretty screenshots, then the following basic instructions — which are correct for a contemporary MacBook and a cheap and cheerful Acer Chromebook as of 2020-07-12 — should suffice:
- On the Mac, cumulate the files to be transferred in directory
Chromebook
-
Zip the directory and save the output to
Chromebook.zip
viazip -r Chromebook.zip Chromebook/
-
Encrypt
Chromebook.zip
and save the output toChromebook.zip.enc
viagpg --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo SHA512 --s2k-cipher-algo AES256 --output Chromebook.zip.enc --symmetric Chromebook.zip
-
Move
Chromebook.zip.enc
to a separate directory and start a simple Python HTTP web server on port8080
in that directory using the wrapper scriptweb-serve-this-directory
viaweb-serve-this-directory -p 8080
-
On the Chromebook, download
Chromebook.zip.enc
viawget http://<ip-address-of-web-serve-this-directory>:8080/Chromebook.zip.enc
-
Decrypt
Chromebook.zip.enc
and save the output toChromebook.zip
viagpg --output Chromebook.zip --decrypt Chromebook.zip.enc
-
Unzip the files in
Chromebook.zip
viaunzip Chromebook.zip
- Enjoy secure file transfer over a poor man’s HTTPS!
Happy? Got what you were looking for in the time you were willing to invest? Fantastic! Now, join the rest of us for how we got there in the first place along with some additional remarks on security.
The Last Leg of a Setup
It took a while to figure out a half way decent solution to installing Visual Studio Code on my cheap and cheerful Acer Chromebook. But it was well worth the effort.
With it came an abundance of familiarity, convenience, and productivity for everything from open source development to writing blog posts as “articles-as-code” in Markdown (yep, also this one).
Well, almost. While I was instantly logged into all Google services by magic of me providing the password upon initial setup, the same was not true for all other non-Google services, unfortunately. They didn’t have the slightest clue it was me trying to access them from a new device. Long story short:
I needed to transfer a substantial amount of secrets from my Mac to my Chromebook. Basically, my entire digital life.
A task which, in my books, easily qualifies as deserving some longer thoughts before eventually being approached with the necessary respect and precautions. The “slow thinking” part of Daniel Kahneman’s best seller, if you want.
Exchanging Secrets in Public
Now, as I was out of removable hard drives at this point in time (and also didn’t want any potential residue secrets lurking around on them), the transport medium of choice was WiFi.
While modern encryption on WiFi is fairly secure for everyday use (you’re using a strong password, aren’t you?!), putting my entire digital life on a couple of electromagnetic waves without any additional protection didn’t seem like the most secure thing to do. Don’t get me wrong:
I’m not paranoid. It’s just that everyone is after me!
With the transport medium sorted, it was time to find a suitable service to serve the secrets with. Unfortunately, SSH was not available and SSL certificates were also in short supply, effectively ruling out a large part of standard cryptographically secured transport mechanisms.
Installing a dedicated application seemed a bit of an overhead, given this was to be a simple one-off transfer. I wasn’t planning on freely distributing my entire digital life on a regular basis; large parts of the security concept revolved around the ephemeral nature of having to store the secrets outside of the intended target systems.
Moreover, whatever the eventual exchange mechanism, it would have to also bridge macOS and ChromeOS. Ideally, bi-directional and without having to install any additional components.
When All You Have Are Standard Tools
Back to readily available standard operating system tools then that came pre-installed on both macOS and Chrome OS. Now, enabling Linux Apps (Beta) had in fact installed a Linux VM on the Chromebook with most of the standard Linux tools already on it.
At this point, what both systems did ship with was not so different from a lot of other BSD or Linux distributions. Most notably,
Both macOS and ChromeOS came with Python and OpenSSL pre-installed.
Inspired by a SuperUser reply, it turns out that
That’s sufficient to construct a poor man’s HTTPS, leveraging Python for the HTTP part while leaving OpenSSL to take care of the S(ecurity) bit.
Fantastic! Problem solved?! Unfortunately, no. As detailed in a StackExchange reply,
OpenSSL is not fit for general purpose encryption.
Not good. However, a more suitable replacement for openssl
was already included in the reply as well, as it recommended the use of GNU Privacy Guard (in short: GnuPG). Best of all,
GnuPG could easily be installed on macOS via
brew install gnupg
when leveraging Homebrew as the package manager.
While technically not entirely using readily available standard operating systems tools across all systems involved, using GnuPG did provide a more secure encryption solution. However, there were still some pitfalls to be circumvented to eventually arrive at a simple but secure poor man’s HTTPS.
A Step-By-Step Guide
In the spirit of modern systems and software architecture, the below is merely the result of carefully sellotaping together a collection of GitHub and StackOverFlow pages that provided me with valuable answers on my end-to-end journey.
On the Mac
The first part, which occurred on my Mac, involved cumulating the files to be transferred, zipping them up, and encrypting them, before eventually serving them via the Python web server wrapper script web-serve-this-directory
.
Cumulating the Files to be Transferred
For convenience reasons, the HTTP transfer did only involve a single encrypted archive. Hence, the first step was to cumulate all files to be transferred in a single directory. For this, a new directory Chromebook
was created via
mkdir -p Chromebook
and files secrets-1.file
, secrets-2.file
, and so on copied to the Chromebook
directory via
cp secrets-1.file Chromebook/
cp secrets-2.file Chromebook/
...
Zipping the Directory
With all files to be transferred copied to directory Chromebook
, the contents of the directory were zipped up to output file Chromebook.zip
via
zip -r Chromebook.zip Chromebook/
Encrypting the ZIP File
Subsequently, Chromebook.zip
was encrypted using gpg
and the output saved to Chromebook.zip.enc
, using the additional secure settings suggested in a StackExchange reply, via
gpg --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo SHA512 --s2k-cipher-algo AES256 --output Chromebook.zip.enc --symmetric Chromebook.zip
If you are aware of the security implications and are happy to accept the risks, then Chromebook.zip
can also be encrypted using openssl
, as suggested in a SuperUser reply, via
openssl enc -aes-256-cbc -md sha512 -salt -in Chromebook.zip -out Chromebook.zip.enc
Here, the default version LibreSSL 2.6.5
of openssl
on my Mac is slightly (*cough*, *cough*) behind the official LibreSSL releases. More recent versions can again be installed via Homebrew and enabled as outlined in a StackOverflow reply.
As for the default version, providing the -md sha512
option allows to at least mitigate some of the insecurities of OpenSSL. If permitted by your version, also provide options -pbkdf2 -iter 100000
for some increased security as outlined in a StackExchange reply.
Regardless of the encryption method, make sure to provide a secure password and also remember it as it will be needed again later on. As for some general guidance on password strength
Transferring the Encrypted ZIP File
Before making the encrypted ZIP file Chromebook.zip.enc
available via a web server, it was moved to the dedicated directory webserver
to avoid accidentally sharing other files, such as the unencrypted ZIP, file as well. This was achieved via
mkdir -p webserver
mv Chromebook.zip.enc webserver/
cd webserver/
A simple Python HTTP web server was started on port 8080
using the wrapper script web-serve-this-directory
via
web-serve-this-directory -p 8080
Here, make a note of the IP address the Python web server is starting on; in my case, it was 10.0.0.241
as per below screenshot.
On the Chromebook
The second part, which occurred on my Chromebook, involved downloading the encrypted file from the Mac’s web server, decrypting, and eventually unzipping it.
Downloading the Encrypted ZIP File
On the Chromebook, the Terminal application was launched that came as part of enabling Linux Apps (Beta) and the encrypted file Chromebook.zip.enc
downloaded from the Python HTTP web server running on the Mac via
wget http://<ip-address-of-web-serve-this-directory>:8080/Chromebook.zip.enc
Decrypting the ZIP File
The local file Chromebook.zip.enc
was decrypted and the output saved to file Chromebook.zip
using gpg
via
gpg --output Chromebook.zip --decrypt Chromebook.zip.enc
In case you accepted the associated security risks by using openssl
, local file Chromebook.zip.enc
can be decrypted using openssl
and the output saved to file Chromebook.zip
via
openssl enc -d -aes-256-cbc -md md5 -in Chromebook.zip.enc -out Chromebook.zip
Here, as of 2020-07-12, the option -md md5
was required for backwards compatibility as outlined in a StackOverflow reply; note that this also indirectly points out the use of MD5 as one of the weaknesses of using OpenSSL for general purpose file encryption.
Regardless of the encryption method, supply the password provided when encrypting the file on the Mac in the first place.
Unzipping the ZIP File
The contents of Chromebook.zip
were unzipped to directory Chromebook
via
unzip Chromebook.zip
In case unzip
is not installed on the Chromebook by default, it can be installed via
sudo apt-get install unzip
The final result on my Chromebook eventually presented itself as in below screenshot
More Scalable Solutions
The process described above provides a secure file exchange mechanism built (almost) solely on readily available operating system tools across machine boundaries.
It’s great for ephemeral one-off file transfers when little else is available. However, the approach doesn’t really scale well. For repeated transfers or additional features such as audit-ability, it’s more effective to use a dedicated solution.
Options for exclusively locally provided solutions range from secure general purpose services such as SSH and HTTPS servers to specialised file services such as SFTP, NAS servers, and private clouds the likes of ownCloud or Nextcloud.
Options for internet-based file exchange services are seemingly endless and vary as providers come and go. Whether to leverage them or to keep personal data solely local is a personal choice.
So, How do You Exchange Files?!
While the above Worx for Me!™ when it comes to securely exchanging files between two machines over HTTP, you may have an alternative or better way.
Think this is all rubbish, massively overrated, or heading into the absolutely wrong direction in general?! Feel free to reach out to me on LinkedIn and teach me something new!
As always, prove me wrong and I’ll buy you a pint!
Subscribe to How Hard Can It Be?!
Get the latest posts by following us on LinkedIn and Twitter