Secure your Bitcoins with Gmail and Keybase


I've invested a few BTC and ETH funds over the past few months in a very speculative way (whether it's a smart thing to do or not is probably the subject of another post) and a very simple need arose: secure these coins out of the marketplaces where I acquired them. I'm already taking quite a lot of risk exposing myself to BTC or ETH so I definitly don't want to expose myself to the risk of default of the marketplaces I use on top of that.

A quick search online yielded the following solutions:

Not being a Bitcoin power-user but more of an occasional coin investor (mostly motivated by curiosity and fun-seeking), I really don't want to setup a paper wallet or a cold USB wallet (I know I'd just eventually loose them) and I'm not keen on spending money on a hardware wallet.

I really just want to generate a wallet and store it securely on my GMail account so that I'm sure that I'll be able to retrieve it eventually, at some point.

So I opted for the following solution relying on GMail[3] and Keybase[4] that I find strike the right balance between ease of use, durability and security, at least for me. I'll describe that solution for Bitcoin but it is easily adaptable to other currencies.

You'll need the following:

Setting up the wallet

Create new directory that we'll use to install a few npm (node) packages. Once finished you can delete that directory.

$ mkdir bitcoin_wallet
$ cd bitcoin_wallet

Install the library we'll need to work with Bitcoin addresses.

$ npm install --save bitcoinjs-lib

From there you can start the NodeJS REPL (ctrl-D to exit).

$ node

We'll use BitcoinJS to generate a Bitcoin address locally. Please note that if your computer is compromised, this address might be intercepted by an attacker (I'll try to point out all the security assumptions I'm making along the way).

> var bitcoin = require('bitcoinjs-lib')
> var keyPair = bitcoin.ECPair.makeRandom()
> keyPair.toWIF()
> keyPair.getAddress()

Securing your private key

The string returned from the `toWIF()` call is your private key. The string returned by `getAddress()` is your Bitcoin address. Copy-paste both of them in keybase.io/encrypt and add yourself as recipient. After clicking `Encrypt` you should get a PGP encrypted representation of your key:

Version: Keybase OpenPGP v2.0.71
Comment: https://keybase.io/crypto


At this point you trust PGP with your key and the fact that your computer is not compromised (since the PGP encryption happened client-side with Keybase). You also trust Keybase to do what they say they're doing. I personally feel good with these assumptions given the amount of Bitcoin I'm trying to secure, but you might totally feel differently about it.

You can store that encrypted key on your computer or, to make sure that you won't loose it, send it to yourself on Gmail or any other cloud email or storage service that you trust you will be using for a long time.

Out of convenience, make sure to store your Bitcoin address in clear along with the PGP encrypted message.

Gmail or anyone getting access to the PGP encrypted version of it won't be able to retrieve your private key.

Testing your setup

To test your setup, send a small amount of Bitcoin to your address (the value returned from `getAddress()` above) using your favorite wallet or by withdrawing a small amount from the marketplace you use.

Even if transactions take a bit of time to confirm these days, it should instantaneously be visible as unconfirmed on blockchain.info (using the address we generated in this tutorial here):


Wait for a few hours for the transaction to confirm before proceeding to sending the money back to the marketplace you're using (they should allow deposit directly to a Bitcoin address) or your favorite wallet. Note the ID of the transaction (this is the longest string).

Make sure to send a small amount in case you are unable to use the Bitcoin address and private key you generated.

Now let's attempt to generate a reverse transaction to a Bitcoin address of your choice. Retrieve your encrypted blob and copy paste it at keybase.io/decryot. Once successfully decrypted, use your private key, along with the ID of your test transaction with the following code to generate a transaction from the NodeJS REPL:

> var bitcoin = require('bitcoinjs-lib')
> var txID = 'b4d9aaad6ac7265db0a368c6158374a7817dc5513eeebc2e4e1ea7bf529d35c0'
> var WIF = 'L5CuJMArhoEHd2aRgduovHAeCRS7WqGSjFCDyHZGrjyLPKnDL9Rf'
> var destAddress = '1NVMjvHX6iF2xE5538GnmdxBj6gZpU8XMx'
> var amountSatoshis = 919000
> var feeSatoshis = 81000
> var keyPair = bitcoin.ECPair.fromWIF(WIF)
> var tx = new bitcoin.TransactionBuilder()
> tx.addInput(txID, 0)
> tx.addOutput(destAddress, amountSatoshis-feeSatoshis)
> console.log(tx.build().toHex())

The last value is the hex encoding of your test transaction to `destAddress`. You can then submit that transaction at https://blockchain.info/pushtx. If you receive a `Transation Submitted` that means that you successfully manage to send bitcoins out of your wallet. You can then track the confirmation of the transaction on blockchain.info.


Congrats! You now control a Bitcoin address you can safely send your funds to and use as a vault.

Obviously, you can easily extend this pattern to other cryptocurrencies assuming you have a way to generate new addresses, create and submit transactions.

I hope this post is useful to you, don't hesitate to contact me at polu.stanislas@gmail.com with any remarks or feedback!


[0] https://en.bitcoin.it/wiki/How_to_set_up_a_secure_offline_savings_wallet
[1] https://en.bitcoin.it/wiki/Paper_wallet
[2] https://en.bitcoin.it/wiki/Hardware_wallet
[3] https://gmail.com
[4] https://keybase.io
[5] https://nodejs.org