@pa2013 helpfully posted Alon's BitKey announcement from last week to the Bitcoin Reddit, which sparked an interesting discussion regarding whether or not you can safely trust BitKey to perform air-gapped transactions. I started responding there but my comment got so long I decided to turn it into a blog post.
Air-gaps are not enough
As the astute commenters on Reddit correctly pointed out, just because you are using an offline air-gapped computer doesn't make you safe:
For example an offline computer can have a tainted random number generator, modified to only feed you addresses that the attacker can sweep at a later point in time.
I agree 100%. There are many ways a tainted air-gapped system can betray you, including smuggling out your secret keys via covert channel (e.g., USB keys, high frequency sound, covert activation of Bluetooth/wifi chipset, etc.)
The good news is that:
- Even if you assume BitKey is evil you can still use it to perform a highly secure Bitcoin transactions. Details in the "If I tell you I'll have to kill you" section below.
- Most of the attacks against air-gapped systems are hard to hide if you build your own image from source.
The bad news is that:
Most people won't build from source.
Without deterministic builds you can't tell if the system image you are using is a faithful representation of source code.
A deterministic build means that everyone that builds from source always get exactly the same binary output, bit for bit.
You can't trust RNGs without deterministic builds. A properly designed "evil" RNG looks just like a "good" RNG. Just by observing the output it is possible to prove that an RNG is insecure but absolutely impossible to prove that it is secure.
The makes RNGs the perfect place to hide backdoors. I'd bet money that RNG-level backdoors are where intelligence agencies like the NSA are focusing their efforts to compromise Internet security.
For this reason I personally don't trust RNGs at all when the stakes are high. Any RNG, not just the one in BitKey.
Even if you audit the source code that the RNG is being compiled from, you still have to trust that the compiler is translating source code faithfully, and worse this turns out to be a recursive problem that was recognized was recognized waaaay back:
A solution you don't have to trust is better than one you do
In its current form BitKey is a swiss army knife of handy Bitcoin tools which you could use to implement any workflow. What's interesting is that this includes at least one workflow which don't require you to trust BitKey. I call it the "If I tell you I'll have to kill you" workflow.
But first, we need to recognize that there is an inescapable trade off between convenience and security and since the risk is proportional to the value of your wallet it doesn't make sense to enforce a specific trade off. We want to help make the most paranoid usage model practical for day to day use but at the same time, we want to create tools that let the user decide. For low value wallets maybe you're willing to trade off some security for better usability.
On the flip side, as someone who uses BitKey to perform very high security transactions routinely, once you get the hang of it's not too much trouble to go a bit overboard and sleep well at night. Better safe than sorry.
It turns out you can create secure Bitcoin transactions offline without having to trust the system performing the transaction. Do that and you can mostly dispense with having to trust third parties.
This is a good thing because trusted third parties are a security hole:
Instead of trusting the solution you just have to trust the security protocol and its underlying assumptions, which you can verify yourself.
The trick is:
- Don't use the RNG. Provide your own entropy. Use a dice!
- Assume BitKey is evil. Work around that by enforcing a strict flow of information to prevent it from betraying you.
For example, let's say there are two computers: BLUE and RED.
I'm calling this the "If I tell you I'll have to kill you" model because once you give BitKey access to the secret keys in your wallet you assume it will try anything to smuggle them out back to the attacker. To prevent that you will have to quarantine BitKey, get the signed transaction out, then kill it.
Now let me translate how that works in practice.
BLUE is a regular Internet connected PC, running a watch wallet (e.g., BitKey in cold-online mode, or Ubuntu running Electrum in watch-only mode). Connected to BLUE PC is a BLUE usb drive.
RED PC is an air-gapped PC that has no hard drive, NIC, Wifi, Bluetooth, sound card, etc. It only has a keyboard, monitor and USB port.
Next to RED is a RED usb drive. It is NOT plugged into RED. (yet)
On BLUE you create an unsigned transaction and save it to a BLUE usb drive.
On RED you boot BitKey into RAM (e.g., in cold-offline mode). You then plug in the BLUE usb drive and copy over the unsigned transaction into RAM. Then you unplug the BLUE usb drive.
At this point RED has the unsigned transaction in RAM but it can't sign it yet because it doesn't have access to the wallet.
So you plug into RED the RED usb drive that contains the wallet. You sign the transaction. You encode the JSON of the signed transaction as a QRcode. You read the QRcode with your phone. Verify that the inputs and outputs are correct. You broadcast the signed transaction to the Blockchain from your phone.
Then you reboot the RED airgapped computer and leave it turned off for a few minutes to take sure the wallet has been wiped from RAM.
The only thing coming out of RED is the QRcode for the signed transaction and you can verify that with a very simple app on a separate device like your phone.
It's not perfect security, because an evil BitKey might conspire with an evil phone by creating an evil QRcode that sends your Bitcoins to another address or leak your private key.
But it's as close as you can get without doing the transaction in your head, and BitKey has all the tools to let you do that.
Areas for improvement
- Improve usability by adding a self-documenting wizard:
Improve usability and reduce the potential for human error by adding a wizard mode in which BitKey guides you step by step in performing secure air-gapped Bitcoin transactions.
- Port BitKey to work on the Raspberry Pi:
I recently bought a few Raspberry Pis for this purpose. A $35 air-gap running BitKey on super cheap open hardware woud not only be cheap and practical it would also prevent us from having to trust our PCs / laptops not to be compromised at the hardware level. On a typical laptop / PC there are way too many places for bad stuff to hide, though I expect the truly paranoid will wrap their Raspberry Pi's in tinfoil just in case.
Also, I think this would be a great opportunity to get TurnKey in general working on the Raspberry Pi.
How deterministic builds fit into the puzzle
Deterministic builds are another way around the problem of having to trust third parties. As seen above, we can get very good security without them, but only by assuming the system we are using is already compromised and limiting how the poison can spread.
But for many applications that just isn't practical. Often you need a two way information flow (e.g., privacy applications) and there are too many ways for a malicious system to betray you.
Full system deterministic builds are going to be essential for those usage scenarios. It's not a silver bullet but unless everyone's build system is compromised, you can at least rely on the translation of source code to binary is faithful.
This improves security dramatically because:
With deterministic builds you don't have to trust us not to insert backdoors into the binary version of BitKey.
I trust myself not to do that but coming from a military security background I can easily emphasize with anyone that doesn't.
You also don't have to trust us to be capable of resisting attacks by Advanced Persistent Threats (AKA super hackers) that might figure out how to worm their way into our development systems.
Personally, I believe it is unwise to expect any single individual or organization to resist truly determined attacks. If the NSA wants into your system they are going to get in.
The problems with deterministic builds are:
- You still need to audit millions of lines of source code.
- We don't have full-system deterministic builds yet. Nobody does. That's something a lot of people in the free software world are working on though.