Author

Topic: Safe way to generate paper wallets (Read 3053 times)

sr. member
Activity: 437
Merit: 415
1ninja
December 24, 2012, 11:23:56 PM
#20
I've recently put together a shell script that just uses OpenSSL to generate a key, which should work from an offline computer as paranoid as you want to make it. It's based on an older "Bitcoin off the grid" script. Since it doesn't do any of the math itself, it hopefully reduces the audit problem to auditing OpenSSL, which is presumably acceptable for most people's purposes.

+1

Using a LiveCD and typing in your shell script is the safest method... (excluding the split key method mentioned above).

1) Signed ISO liveCD.
2) no virus delivery mechanism (except the system hardware)
3) open SSL random number generator
4) small shell script to test and review
sr. member
Activity: 437
Merit: 415
1ninja
December 24, 2012, 10:42:11 PM
#19
To safely generate a key there is a new feature in the Vanity Wallet on bitaddress.org
You need to make a split key and it will work even on a compromised computer. It requires using two computers that are not under the control of the same hacker. For example using your computer at home and one at work.

Open your saved bitaddress on your HOME computer and go to the Vanity Wallet tab. Click generate on Step 1. Print the page. We will call this key pair A. Copy and paste the public key into an email and send it to yourself at WORK.

Open your saved bitaddress on your WORK computer and go to the Vanity Wallet tab. Click generate on Step 1. Print the page. We will call this key pair B. Copy and paste the public key B into an input box for Step 2. Then get public key A from the email you sent above and paste it into the other input box for Step 2.

Select Add and click Calculate Vanity Wallet. You will now have a secure Bitcoin address for saving.

When you later go to combine the private keys on one computer to get your coins out of savings then sweep the whole balance and don't use that same address anymore for savings. Consider it compromised.
legendary
Activity: 1792
Merit: 1008
/dev/null
December 24, 2012, 10:18:31 PM
#18
My last post got me to thinking about what is the very least amount of code to generate private keys completely transparently - where you could see in one glance that nothing is possibly amiss.

And so I took that keyconv program and hacked it into a very simple single text that anyone can paste into a file and compile. Just the math and here it is:

---snip---

thanks for the lovely C code Wink
pc
sr. member
Activity: 253
Merit: 250
December 24, 2012, 10:06:01 PM
#17
I've recently put together a shell script that just uses OpenSSL to generate a key, which should work from an offline computer as paranoid as you want to make it. It's based on an older "Bitcoin off the grid" script. Since it doesn't do any of the math itself, it hopefully reduces the audit problem to auditing OpenSSL, which is presumably acceptable for most people's purposes.
sr. member
Activity: 437
Merit: 415
1ninja
December 24, 2012, 08:41:08 PM
#16
I want to start spreading out my coins in multiple paper wallets. bitaddress.org is cool, but I don't think I have any guarantees that those keys aren't being logged. I saw an idea someone else had about disconnecting your computer from the internet after the page is loaded, then generate the keys.

Just looking for some tips and pointers to properly store my investment. I don't want to make a mistake and lose 'em all.

To avoid the chance of code poisoning save the bitaddress.org page (HTML only) and check the SHA1 hash which you can do on Windows with a downloadable GUI program OR using an online tool. Then you don't have to worry about your keys being uploaded somewhere.

How to avoid keyboard logging threat in my next post...
sr. member
Activity: 437
Merit: 415
1ninja
December 24, 2012, 07:23:59 PM
#15
But the absolute safest way (we're talking maximum paranoia here) is to use the openssl lib offline on a livecd after verifying the ISO's hash.

+1

You will need to get the Bitcoin address from the private key somehow. You can use a saved version of bitaddress.org for that. That brings up the issue of using a USB drive with the livecd to get bitaddress.org onto the machine booted with the livecd.

If we have our tin foil hats on then we cannot trust USB drives as they are a virus delivery medium.
sr. member
Activity: 293
Merit: 250
December 23, 2012, 04:04:08 PM
#14
You don't have to like Armory, I just don't know why you wouldn't try it first, since it was designed for precisely what the OP requested.

I do like Armory. In fact it has been my client of choice for quite some time. But the absolute safest way (we're talking maximum paranoia here) is to use the openssl lib offline on a livecd after verifying the ISO's hash.
hero member
Activity: 812
Merit: 1006
December 23, 2012, 01:41:33 PM
#13
when typing the keys for the brainwallet, the sound, visual image or electrical microcharges could be monitored by a microphone, a camera or a special radio.

the electrical connection of the pc to the monitor could leak into the electrical circurits and from there, recorded as well.

a low-level firmware driver in you CDROM drive could record something, send it back to the manufacturer.

You win 10 tinfoil-hat points. Hooray!
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
December 23, 2012, 01:16:22 PM
#12
My last post got me to thinking about what is the very least amount of code to generate private keys completely transparently - where you could see in one glance that nothing is possibly amiss.

And so I took that keyconv program and hacked it into a very simple single text that anyone can paste into a file and compile. Just the math and here it is:

This is the best solution I've seen so far.

There's nothing wrong with bitaddress.org but it will take ages to go through the code. Especially the ECDSA math.

If you have the skill & patience & background to go through code to verify an implementation, then I suppose this works for you.

But seriously, I made Armory specifically to make cold storage accessible to the users that don't want to dig through code, write their own, etc.  It has been in user for a year now, without anyone ever losing coins.  Put Armory on your offline computer, generate a wallet, print a paper backup (or copy by hand if you don't have an acceptable printer).  This is the best kind of "paper wallet" because it is a single code that protects all addresses ever created by the wallet.  If you ever need to restore the wallet, you only type in that code, instead of 300 individual private keys.

"Create Watching-Only Copy" from the wallet properties window and import it into Armory on your online computer.  You can still generate millions of receiving addresses and verify incoming payments with this wallet, yet an attacker cannot compromise it without physically gaining access to the offline computer -- because your private keys are not even touching the internet.  

And if that's not enough, you can use a USB key to move tx data over to the offline computer, sign it, bring it back and hit "broadcast."  It takes about 60 seconds once you get the hang of it.  

You don't have to like Armory, I just don't know why you wouldn't try it first, since it was designed for precisely what the OP requested.
sr. member
Activity: 293
Merit: 250
December 23, 2012, 05:21:18 AM
#11
My last post got me to thinking about what is the very least amount of code to generate private keys completely transparently - where you could see in one glance that nothing is possibly amiss.

And so I took that keyconv program and hacked it into a very simple single text that anyone can paste into a file and compile. Just the math and here it is:

This is the best solution I've seen so far.

There's nothing wrong with bitaddress.org but it will take ages to go through the code. Especially the ECDSA math.
legendary
Activity: 882
Merit: 1000
December 23, 2012, 02:45:13 AM
#10
Go to bitaddress.org, save page as some.htm. Go to saved location, open it there. Bam. No internet connection to site.
donator
Activity: 294
Merit: 250
December 23, 2012, 12:45:10 AM
#9
http://bitcoinarmory.com/index.php/using-offline-wallets-in-armory

Offline wallets using armory are about as safe as it gets... right?

Also extremely easy to set up and use.
hero member
Activity: 763
Merit: 500
December 22, 2012, 06:48:25 PM
#8
Thoughts?
when typing the keys for the brainwallet, the sound, visual image or electrical microcharges could be monitored by a microphone, a camera or a special radio.

the electrical connection of the pc to the monitor could leak into the electrical circurits and from there, recorded as well.

a low-level firmware driver in you CDROM drive could record something, send it back to the manufacturer.

legendary
Activity: 1904
Merit: 1037
Trusted Bitcoiner
December 22, 2012, 05:47:42 PM
#7
you need a usb drive with the bitaddress.org page and a cd with a live Linux cd handy.

but a cheep and dirty way would be take your computer offline, generate, print, reboot.
legendary
Activity: 1862
Merit: 1114
WalletScrutiny.com
December 22, 2012, 03:39:06 PM
#6
The browser implementations look safe when you switch off your wifi but be aware that it could still use poor randomness or hard-coded keys to snatch your bitcoin. Being offline does not protect you. You need to get code review done by experts. With your life savings I guess you can't be paranoid enough. Maybe use the 5 most plausible approaches and split up your savings Wink
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
December 22, 2012, 11:36:32 AM
#5
Why not just install Armory on an offline computer, and print off your paper backup?  You can even print off the first 100 keys by clicking on "Backup Individual Keys", if you so desire.  

I essentially made Armory just for this purpose... so people don't have to go through crazy command-line, messy compiling operations to get keys offline.  If you're willing to keep a computer offline for this purpose, then you can use Armory exactly as it was intended:  in addition to printing a paper backup, you "Create a watching-only copy", put it on your online computer, and then you can manage all your BTC without risk of an attacker getting them (the watching-only wallet holds no private keys).  Generate addresses for your offline wallet, watch your balance, confirm incoming transactions...

If you do the paper backup alone, you're going to have a hell of a time spending or moving those coins.  If you do it the Armory way, you use the online computer to create the unsigned transaction, take the tx to the offline computer (or reboot into the offline OS), sign the tx, and then take it back to the online computer to broadcast.  It takes about 60 seconds to execute the whole process.

http://bitcoinarmory.com/

hero member
Activity: 784
Merit: 1009
firstbits:1MinerQ
December 22, 2012, 11:13:05 AM
#4
My last post got me to thinking about what is the very least amount of code to generate private keys completely transparently - where you could see in one glance that nothing is possibly amiss.

And so I took that keyconv program and hacked it into a very simple single text that anyone can paste into a file and compile. Just the math and here it is:

Code:
#include
#include
#include
#include

#include
#include
#include
#include

#if !defined(_WIN32)
#include
#else
#include "winglue.h"
#endif

const char *vg_b58_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

void vg_b58_encode_check(void *buf, size_t len, char *result)
{
unsigned char hash1[32];
unsigned char hash2[32];

int d, p;

BN_CTX *bnctx;
BIGNUM *bn, *bndiv, *bntmp;
BIGNUM bna, bnb, bnbase, bnrem;
unsigned char *binres;
int brlen, zpfx;

bnctx = BN_CTX_new();
BN_init(&bna);
BN_init(&bnb);
BN_init(&bnbase);
BN_init(&bnrem);
BN_set_word(&bnbase, 58);

bn = &bna;
bndiv = &bnb;

brlen = (2 * len) + 4;
binres = (unsigned char*) malloc(brlen);
memcpy(binres, buf, len);

SHA256(binres, len, hash1);
SHA256(hash1, sizeof(hash1), hash2);
memcpy(&binres[len], hash2, 4);

BN_bin2bn(binres, len + 4, bn);

for (zpfx = 0; zpfx < (len + 4) && binres[zpfx] == 0; zpfx++);

p = brlen;
while (!BN_is_zero(bn)) {
BN_div(bndiv, &bnrem, bn, &bnbase, bnctx);
bntmp = bn;
bn = bndiv;
bndiv = bntmp;
d = BN_get_word(&bnrem);
binres[--p] = vg_b58_alphabet[d];
}

while (zpfx--) {
binres[--p] = vg_b58_alphabet[0];
}

memcpy(result, &binres[p], brlen - p);
result[brlen - p] = '\0';

free(binres);
BN_clear_free(&bna);
BN_clear_free(&bnb);
BN_clear_free(&bnbase);
BN_clear_free(&bnrem);
BN_CTX_free(bnctx);
}

void vg_encode_privkey(const EC_KEY *pkey, int addrtype, char *result)
{
        unsigned char eckey_buf[128];
        const BIGNUM *bn;
        int nbytes;

        bn = EC_KEY_get0_private_key(pkey);

        eckey_buf[0] = addrtype;
        nbytes = BN_num_bytes(bn);
        assert(nbytes <= 32);
        if (nbytes < 32)
                memset(eckey_buf + 1, 0, 32 - nbytes);
        BN_bn2bin(bn, &eckey_buf[33 - nbytes]);

        vg_b58_encode_check(eckey_buf, 33, result);
}

void vg_encode_address(const EC_POINT *ppoint, const EC_GROUP *pgroup, int addrtype, char *result)
{
        unsigned char eckey_buf[128], *pend;
        unsigned char binres[21] = {0,};
        unsigned char hash1[32];

        pend = eckey_buf;

        EC_POINT_point2oct(pgroup,
                           ppoint,
                           POINT_CONVERSION_UNCOMPRESSED,
                           eckey_buf,
                           sizeof(eckey_buf),
                           NULL);
        pend = eckey_buf + 0x41;
        binres[0] = addrtype;
        SHA256(eckey_buf, pend - eckey_buf, hash1);
        RIPEMD160(hash1, sizeof(hash1), &binres[1]);

        vg_b58_encode_check(binres, sizeof(binres), result);
}

int main(int argc, char **argv)
{
char ecprot[128];
char pbuf[1024];
EC_KEY *pkey;
unsigned char *pend = (unsigned char *) pbuf;

int count = argc > 1 ? atoi(argv[1]) : 1;

OpenSSL_add_all_algorithms();

while(count-- > 0) {
pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_KEY_generate_key(pkey);
i2o_ECPublicKey(pkey, &pend);
vg_encode_address(EC_KEY_get0_public_key(pkey), EC_KEY_get0_group(pkey), 0, ecprot);
printf("Address: %s\n", ecprot);
vg_encode_privkey(pkey, 128, ecprot);
printf("Privkey: %s\n\n", ecprot);
}
}



Paste that into a file named "mickey.c" and make sure you have the openssl dev library (libssl-dev) and the C compiler. Run this command to compile:

gcc -o mickey mickey.c -lcrypto

And you have "mickey" the worlds simplest self contained and easily reviewable key generator. It even can take a "count" argument. eg.

Code:
./mickey 3
Address: 18uiqewQRU5KNb6ksPsm9itm7ox918bLCn
Privkey: 5K6GN9Rs7XWQPk351Cb8KN3rjW524iTzt1iiAxgJWpqruGmShB9

Address: 16fzTFM3CspVyzgHg1jTYF8MkVC8rX5vEQ
Privkey: 5HzvE29u9X1t3bXHRyX3SN5TEFJB3ezAq9xznV2oKDGc5wrM4NB

Address: 1HsFVnD5aejdU1PMSFg3utBRxu6CZtP8Pm
Privkey: 5JJdNRv7sRmmTdzJdz8UdHYmHBGUXiRrksMSGxjbhDPbGu6Anin

I don't have windows handy to check but I think it should work with a small change to the compile command.

On linux you can also directly send the output to your printer,

mickey 3 | lpr

And, just for fun, if you have the qrencode pkg installed (sudo apt-get install qrencode) then this gives you a QR code of a private key,

mickey |grep Privkey |cut -d\  -f2 |qrencode -o key.png
hero member
Activity: 784
Merit: 1009
firstbits:1MinerQ
December 22, 2012, 06:59:13 AM
#3
You can also get the keyconv tool that comes with vanitygen. Ideally you would compile it yourself but binaries are readily available. This tool can generate keys with the -G option. The nice thing about this is the source code is quite short so with even a very modest understanding of code you can review it yourself in about 1 minute. Then you know it's not logging anything back to the mother ship. (hint - the generate function is about 10 lines and has no net/comm code at all)

Code:
if (generate) {
                unsigned char *pend = (unsigned char *) pbuf;
                addrtype = 0;
                privtype = 128;
                EC_KEY_generate_key(pkey);
                res = i2o_ECPublicKey(pkey, &pend);
                fprintf(stderr, "Pubkey (hex): ");
                dumphex((unsigned char *)pbuf, res);
                fprintf(stderr, "Privkey (hex): ");
                dumpbn(EC_KEY_get0_private_key(pkey));
                vg_encode_address(EC_KEY_get0_public_key(pkey),
                                  EC_KEY_get0_group(pkey),
                                  addrtype, ecprot);
                printf("Address: %s\n", ecprot);
                vg_encode_privkey(pkey, privtype, ecprot);
                printf("Privkey: %s\n", ecprot);
                return 0;
        }

Personally I'd just use bitaddress.org offline. I reviewed it's code myself once long ago and there wasn't any nasties in there. It's also not that long to view as it can be done in maybe 10 minutes within your browser - "right click, view source". I realize not everyone can do this but in this community you can be sure any weirdness would be fodder for a 25 page war drum thread.
hero member
Activity: 812
Merit: 1006
December 22, 2012, 06:31:38 AM
#2
Not tinfoil-hat-proof, but pretty safe if you trust your web browser and your printer manufacturer:

- In chrome/firefox/other browser open incognito window / private window / whatever it is called
- Open bitaddress.org
- Close all internet connections
- Do the things you do, paper wallet, brainwallet, etc.
- Close the incognito/private browser windows
- Connect to internet again

The risks are that when you print, some reptilian software provider catches the printed  data and stores it somewhere. Or if chrome incognito mode or firefox private mode are not really what they promise.

Thoughts?
legendary
Activity: 1022
Merit: 1001
I'd fight Gandhi.
December 22, 2012, 05:26:35 AM
#1
I want to start spreading out my coins in multiple paper wallets. bitaddress.org is cool, but I don't think I have any guarantees that those keys aren't being logged. I saw an idea someone else had about disconnecting your computer from the internet after the page is loaded, then generate the keys.

Just looking for some tips and pointers to properly store my investment. I don't want to make a mistake and lose 'em all.
Jump to: