pc (OP)
|
|
December 25, 2012, 03:01:55 AM |
|
I've been intrigued for a while by the use of bitaddress.org and Bitcoin off-the-grid (BOTG) to generate keys for secure storage (and gift-certificate-like paper keys). I particularly liked how BOTG just used basic things that were part of most linux-like systems and straight OpenSSL to generate the keys. (While I think bitaddress.org's code is probably fine, I'm a little paranoid about using Javascript to generate the random numbers, and OpenSSL is basically the standard.) Also, I wanted to play around with learning zsh scripting. I used a lot of the code from BOTG, but adapted it in several ways: (1) Zsh is a little different than most shells, and so I had to make a couple tweaks (like 1-indexing arrays), (2) I'm on a Mac, and a couple of the utilities it used weren't available. (Though for all I know, this won't work on a linux system now), (3) I wanted to support the full range of keys that OpenSSL generated, rather than just most of them (I think that BOTG eliminated about a bit of private key availability, not that it [em]really[/em] matters), (4) I'm not convinced that the BOTG address-generating code worked for addresses that were less than 34 characters, and though I might have I redid it anyway. I very much appreciate the BOTG base, and it handles a lot more things than this code does. This is just a way to generate a key with OpenSSL and find its address, so that one can send coins there and then later import the key into a wallet. Any contributions here which are mine I put into the public domain. (And as usual, no warranty, while I've tested it for my purposes and it seems good to me and I plan to use it, there's of course the chance of a subtle bug that will mean you can't get your coins or something.) To run, just put the code in a file and mark it executable. Pass an argument of "1" if you'd like to see all the details of the OpenSSL key to check everything. #!/bin/zsh debug=$1 base58=(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z a b c d e f g h i j k m n o p q r s t u v w x y z)
capitalizeHex() { tr "[a-f]" "[A-F]" }
encodeBase58() { initialones=$(sed -e 's/\(\(00\)*\).*/\1/' -e 's/00/1/g' <<<$1) echo -n $initialones bc <<<"ibase=16; n=$1; while(n>0) { n%3A ; n/=3A }" | tail -r | while read n do echo -n ${base58[n+1]} done }
checksum() { xxd -p -r <<<"$1" | openssl dgst -sha256 -binary | openssl dgst -sha256 -binary | xxd -p -c 80 | head -c 8 | capitalizeHex }
hexToAddress() { echo "$(encodeBase58 "$2$1$(checksum "$2$1")")" }
privatekey=$(openssl ecparam -genkey -name secp256k1 -noout) openssldescription=$(openssl ec -text <<<$privatekey 2>/dev/null) privatekeyhex=$(head -5 <<<$openssldescription | tail -3 | fmt -120 | sed -e 's/[: ]//g' -e 's/^00//' | awk '{printf "%064s\n", $0}' | capitalizeHex) publickeyhashhex=$(openssl ec -pubout -outform DER <<<$privatekey 2>/dev/null | tail -c 65 | openssl dgst -sha256 -binary | openssl dgst -rmd160 -binary | xxd -p -c 80 | capitalizeHex) address=$(hexToAddress $publickeyhashhex "00") privatekeywif=$(hexToAddress $privatekeyhex "80")
(( $debug )) && echo $openssldescription echo "Private Key Hex:" $privatekeyhex echo "Private Key WIF:" $privatekeywif (( $debug )) && echo "Public Key Hash:" $publickeyhashhex echo "Address:" $address
|
|
|
|
K1773R
Legendary
Offline
Activity: 1792
Merit: 1008
/dev/null
|
|
December 25, 2012, 03:12:36 AM |
|
2. how about making a POSIX version? (runs on every *nix, atleast it should)
|
[GPG Public Key]BTC/DVC/TRC/FRC: 1 K1773RbXRZVRQSSXe9N6N2MUFERvrdu6y ANC/XPM A K1773RTmRKtvbKBCrUu95UQg5iegrqyeA NMC: N K1773Rzv8b4ugmCgX789PbjewA9fL9Dy1 LTC: L Ki773RBuPepQH8E6Zb1ponoCvgbU7hHmd EMC: E K1773RxUes1HX1YAGMZ1xVYBBRUCqfDoF BQC: b K1773R1APJz4yTgRkmdKQhjhiMyQpJgfN
|
|
|
pc (OP)
|
|
December 25, 2012, 03:19:38 AM |
|
I don't have any particular objection to a POSIX version. I was mainly working on adapting it for my own use, and posted it in case anybody else found it useful. But if somebody wants to tell me what to change to make it POSIX-compliant, I'd be happy to.
|
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3472
Merit: 4801
|
|
December 26, 2012, 03:10:58 PM |
|
I'm also on a Mac and have been thinking about putting something like this together. Thanks for saving me the work, this is great!
|
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3472
Merit: 4801
|
|
December 27, 2012, 01:39:35 AM |
|
I was trying to modify the script to generate a private key and bitcoin address from a passphrase, essentially creating a brainwallet version of your script. If I've generated a 256 bit private key, for example with the following: echo -n "correct horse battery staple" |openssl dgst -sha256
How would I go about determining what the associated public key is? Can I use the openssl command? Something like: echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
|
|
|
|
pc (OP)
|
|
December 27, 2012, 02:09:12 AM |
|
I'm sure there's a way to do it, but getting as far as I did was stretching my knowledge of openssl. (Which is largely why I did it.) When OpenSSL generates a key, it creates a PEM file with all sorts of information beyond the private key, at least the curve being used, but I suspect much more (See the output of "openssl ecparam -name secp256k1 -genkey"). OpenSSL seems to expect all keys to be in either that format or DER format, and I don't know how to construct such a file given just the private key, though I assume that it couldn't be that hard for somebody who actually knew the nuts and bolts of all this, either using some obscure (at least to me) OpenSSL option, or via just smashing some sort of header and footer bytes onto the key. I'll look into it a little, but I suspect you'll need an actual expert here.
|
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3472
Merit: 4801
|
|
December 27, 2012, 02:14:12 AM |
|
. . . I suspect you'll need an actual expert here.
And here I was hoping you were that "actual expert" I'll keep playing with it a bit too. If neither of us comes up with a solution in the next day or two (and no actual experts happen across this discussion), I'll try posting the question in the "Technical Support" sub-forum. I'm not necessarily looking for a solution using "openssl", I'm just looking for something I can run from a command line terminal on a Mac that will give me the appropriate public key if I have the private key.
|
|
|
|
K1773R
Legendary
Offline
Activity: 1792
Merit: 1008
/dev/null
|
|
December 27, 2012, 03:35:59 AM |
|
How would I go about determining what the associated public key is? Can I use the openssl command? Something like: echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
Damn, this is exactly what I've been trying to figure out all day as well No luck here either. openssl dosnt support this.
|
[GPG Public Key]BTC/DVC/TRC/FRC: 1 K1773RbXRZVRQSSXe9N6N2MUFERvrdu6y ANC/XPM A K1773RTmRKtvbKBCrUu95UQg5iegrqyeA NMC: N K1773Rzv8b4ugmCgX789PbjewA9fL9Dy1 LTC: L Ki773RBuPepQH8E6Zb1ponoCvgbU7hHmd EMC: E K1773RxUes1HX1YAGMZ1xVYBBRUCqfDoF BQC: b K1773R1APJz4yTgRkmdKQhjhiMyQpJgfN
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3472
Merit: 4801
|
|
December 27, 2012, 03:56:38 AM |
|
How would I go about determining what the associated public key is? Can I use the openssl command? Something like: echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
Damn, this is exactly what I've been trying to figure out all day as well No luck here either. openssl dosnt support this. Yep, all three of us were noticing that. Any useful suggestion on how to get a public key from a command line terminal on a Mac given a 256 bit private key?
|
|
|
|
K1773R
Legendary
Offline
Activity: 1792
Merit: 1008
/dev/null
|
|
December 27, 2012, 05:37:37 AM |
|
How would I go about determining what the associated public key is? Can I use the openssl command? Something like: echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
Damn, this is exactly what I've been trying to figure out all day as well No luck here either. openssl dosnt support this. Yep, all three of us were noticing that. Any useful suggestion on how to get a public key from a command line terminal on a Mac given a 256 bit private key? armoryengine.py would be the solution!
|
[GPG Public Key]BTC/DVC/TRC/FRC: 1 K1773RbXRZVRQSSXe9N6N2MUFERvrdu6y ANC/XPM A K1773RTmRKtvbKBCrUu95UQg5iegrqyeA NMC: N K1773Rzv8b4ugmCgX789PbjewA9fL9Dy1 LTC: L Ki773RBuPepQH8E6Zb1ponoCvgbU7hHmd EMC: E K1773RxUes1HX1YAGMZ1xVYBBRUCqfDoF BQC: b K1773R1APJz4yTgRkmdKQhjhiMyQpJgfN
|
|
|
DannyHamilton
Legendary
Offline
Activity: 3472
Merit: 4801
|
|
December 27, 2012, 05:50:03 AM |
|
How would I go about determining what the associated public key is? Can I use the openssl command? Something like: echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
Damn, this is exactly what I've been trying to figure out all day as well No luck here either. openssl dosnt support this. Yep, all three of us were noticing that. Any useful suggestion on how to get a public key from a command line terminal on a Mac given a 256 bit private key? armoryengine.py would be the solution! Where do I find this program, how do I trust it (is the source available?) and what is the usage? Something like this? echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A | armoryengine.pl -genPublicKey
|
|
|
|
K1773R
Legendary
Offline
Activity: 1792
Merit: 1008
/dev/null
|
|
December 27, 2012, 07:48:45 AM |
|
How would I go about determining what the associated public key is? Can I use the openssl command? Something like: echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
Damn, this is exactly what I've been trying to figure out all day as well No luck here either. openssl dosnt support this. Yep, all three of us were noticing that. Any useful suggestion on how to get a public key from a command line terminal on a Mac given a 256 bit private key? armoryengine.py would be the solution! Where do I find this program, how do I trust it (is the source available?) and what is the usage? Something like this? echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A | armoryengine.pl -genPublicKey https://github.com/etotheipi/BitcoinArmory
|
[GPG Public Key]BTC/DVC/TRC/FRC: 1 K1773RbXRZVRQSSXe9N6N2MUFERvrdu6y ANC/XPM A K1773RTmRKtvbKBCrUu95UQg5iegrqyeA NMC: N K1773Rzv8b4ugmCgX789PbjewA9fL9Dy1 LTC: L Ki773RBuPepQH8E6Zb1ponoCvgbU7hHmd EMC: E K1773RxUes1HX1YAGMZ1xVYBBRUCqfDoF BQC: b K1773R1APJz4yTgRkmdKQhjhiMyQpJgfN
|
|
|
jim618
Legendary
Offline
Activity: 1708
Merit: 1066
|
|
December 27, 2012, 08:27:12 AM |
|
Another thing you can do with private keys and OpenSSL is create MultiBit encrypted private key export files. You can then import these later into MultiBit, specifying the same encryption password in the UI. The file format is described here: https://github.com/jim618/multibit/wiki/Export%20and%20limited%20import%20of%20private%20keysThe OpenSSL commands to encrypt and decrypt the private key export file are near the bottom of the wiki.
|
|
|
|
BkkCoins
|
|
December 30, 2012, 07:20:49 AM Last edit: December 30, 2012, 08:48:57 AM by BkkCoins |
|
I've created a simple utility that can take hex private keys and output various related data using a format string. So you can give it random data and it outputs WIF keys with address, etc. It currently only takes HEX keys in but if people would find it useful I could have it take WIF keys as well. That would be a bit more of a swiss army bitcoin knife.Now supports either Hex or WIF input keys with autodetection. See my post here, with link to my github misc repo. https://bitcointalk.org/index.php?topic=133350.msg1425723#msg1425723Generate keys from the cmd line, from random data, hexdump -v -e '/1 "%02X"' -n 32 /dev/urandom | keyfmt '%a:%w'
|
|
|
|
mintymark
|
|
December 30, 2012, 02:36:36 PM |
|
To get this to work with Ubuntu, I had to change tail -r to tac.
Both reverse the order of lines in a file.
|
[[ All Tips gratefully received!! ]] 15ta5d1N8mKkgC47SRWmnZABEFyP55RrqD
|
|
|
etotheipi
Legendary
Offline
Activity: 1428
Merit: 1093
Core Armory Developer
|
|
December 30, 2012, 07:22:26 PM Last edit: January 08, 2013, 05:13:22 AM by etotheipi |
|
The predecessor to Armory ( PyBtcEngine) used pure-python implementation of ECDSA. This implementation was created by forum user "Lis" here: http://bitcointalk.org/index.php?topic=23241.0If you plug that into google translate, you'll see that he declared that code to be public domain. It's not exactly fast, but it most definitely works. I was able to create, sign, and verify blockchain transactions with it. It is based on python's native handling of arbitrary-sized integers -- go ahead, open a python shell and type "2**10000" ... you'll see what I mean ) Not only can you verify that the code is just a basic EC library with hardcoded secp256k1 constants, it's stupid easy to wrap in a shell script to get whatever you need out of it. I would recommend using entropy generated from a reliable source (OpenSSL?), and pass that into Lis' script. His script uses the python "random" solely for testing that signing and verification work. But as is mentioned in python's own docs "python's PRNG is wholly unsuitable for cryptographic purposes". EDIT: also, you can use armoryengine.py, but it doesn't use Lis' code anymore... it uses Crypto++ libraries made available to python via SWIG. It has turned out to be pretty simple to compile and run on any Linux (even OSX, because you can use armoryengine.py without any Qt dependencies). But that could be a lot of code just to get to its ECDSA implementation. (you can probably strip out 90% of armoryengine.py, though, and keep just the ECDSA parts) Alternatively, you could extract my wrapper around Crypto++ and use that somehow. It does exactly what you want, and you can use publicly-verifiable download the crypto++ libraries, which have no external dependencies. (use only SecureBinaryData objects and all methods below this line).
|
|
|
|
pc (OP)
|
|
January 08, 2013, 03:01:42 AM |
|
I did play around quite a bit with trying to create a DER file, but without the public key (it looks optional in the format spec), in the hopes that OpenSSL would figure it out and calculate it itself, but OpenSSL would just crash when given it. But, if anyone was using what I originally posted, I've updated it to support compressed public keys as well as generating testnet addresses. It also prints the unhashed public key, which is useful if you're using the key for a multisig address. As before, any aspects original to me I put in public domain, and I sure hope there's no bug that causes you to lose your coins since I'd hate for that to happen, but I'm not going to be held liable if it does. #!/bin/zsh zparseopts h=help v=verbose c=compressed t=testnet if [[ -n $help ]]; then <<EOF generatebitcoinkey Generates a bitcoin key using zsh scripting and OpenSSL -h Print help text -v Verbose output (mainly for debugging) -c Use compressed keys -t Output testnet addresses EOF exit fi
[[ -n $verbose ]] && openssl version
base58=(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L M N P Q R S T U V W X Y Z a b c d e f g h i j k m n o p q r s t u v w x y z)
capitalizeHex() { tr "[a-f]" "[A-F]" }
encodeBase58() { initialones=$(sed -e 's/\(\(00\)*\).*/\1/' -e 's/00/1/g' <<<$1) echo -n $initialones bc <<<"ibase=16; n=$1; while(n>0) { n%3A ; n/=3A }" | tail -r | while read n do echo -n ${base58[n+1]} done }
checksum() { xxd -p -r <<<"$1" | openssl dgst -sha256 -binary | openssl dgst -sha256 -binary | xxd -p -c 80 | head -c 8 | capitalizeHex }
hexToAddress() { echo "$(encodeBase58 "$2$1$(checksum "$2$1")")" }
if [[ -n $compressed ]]; then convform=compressed pubkeybytes=33 wifTag=01 else convform=uncompressed pubkeybytes=65 wifTag= fi
if [[ -n $testnet ]]; then addressPrefix="6F" wifPrefix="EF" else addressPrefix="00" wifPrefix="80" fi
privatekey=$(openssl ecparam -genkey -name secp256k1 -conv_form $convform -noout) openssldescription=$(openssl ec -text -conv_form $convform <<<$privatekey 2>/dev/null) privatekeyhex=$(head -5 <<<$openssldescription | tail -3 | fmt -120 | sed -e 's/[: ]//g' -e 's/^00//' | awk '{printf "%064s\n", $0}' | capitalizeHex) publickeyhex=$(openssl ec -pubout -outform DER -conv_form $convform <<<$privatekey 2>/dev/null | tail -c $pubkeybytes | xxd -p -c 80 | capitalizeHex) publickeyhashhex=$(xxd -r -p <<<$publickeyhex | openssl dgst -sha256 -binary | openssl dgst -rmd160 -binary | xxd -p -c 80 | capitalizeHex) address=$(hexToAddress $publickeyhashhex $addressPrefix) privatekeywif=$(hexToAddress $privatekeyhex$wifTag $wifPrefix)
[[ -n $verbose ]] && echo $openssldescription echo "Private Key Hex:" $privatekeyhex echo "Private Key WIF:" $privatekeywif echo "Public Key:" $publickeyhex [[ -n $verbose ]] && echo "Public Key Hash:" $publickeyhashhex echo "Address:" $address
|
|
|
|
grondilu
Legendary
Offline
Activity: 1288
Merit: 1080
|
|
January 08, 2013, 03:09:25 AM |
|
Notice that xxd might not be present on some Unix system. An alternative is to use the 'pack' perl function. Perl is always present on any decent GNU/linux/Unix system: checksum() { perl -we "print pack 'H*', '$1'" | openssl dgst -sha256 -binary | openssl dgst -sha256 -binary | perl -we "print unpack 'H8', join '', <>" }
|
|
|
|
Scrat Acorns
|
|
January 31, 2013, 10:25:48 AM Last edit: January 31, 2013, 11:14:29 AM by Scrat Acorns |
|
If you intend to use this on a live CD make sure you aren't generating keys on a freshly booted machine. See http://eprint.iacr.org/2006/086.pdf and http://eprint.iacr.org/2012/251.pdfLive CD distributions boot with a preset entropy pool. In theory, generating keys right after you boot will greatly reduce the 256bit keyspace since you have only added a few bits of mouse and IO entropy. You probably need to leave the system on a for a while - maybe even seed /dev/random with microphone data. OpenSSL seeds its PRNG with data from /dev/urandom plus the process ID of the current process. On a normal system this isn't an issue since all distros will save some bytes from /dev/*random on shutdown and use them on startup to seed the PRNG.
|
|
|
|
samadamsbeer
Member
Offline
Activity: 93
Merit: 10
|
|
April 24, 2013, 12:52:18 AM |
|
The predecessor to Armory ( PyBtcEngine) used pure-python implementation of ECDSA. This implementation was created by forum user "Lis" here: http://bitcointalk.org/index.php?topic=23241.0If you plug that into google translate, you'll see that he declared that code to be public domain. It's not exactly fast, but it most definitely works. I was able to create, sign, and verify blockchain transactions with it. It is based on python's native handling of arbitrary-sized integers -- go ahead, open a python shell and type "2**10000" ... you'll see what I mean ) Not only can you verify that the code is just a basic EC library with hardcoded secp256k1 constants, it's stupid easy to wrap in a shell script to get whatever you need out of it. I would recommend using entropy generated from a reliable source (OpenSSL?), and pass that into Lis' script. His script uses the python "random" solely for testing that signing and verification work. But as is mentioned in python's own docs "python's PRNG is wholly unsuitable for cryptographic purposes". EDIT: also, you can use armoryengine.py, but it doesn't use Lis' code anymore... it uses Crypto++ libraries made available to python via SWIG. It has turned out to be pretty simple to compile and run on any Linux (even OSX, because you can use armoryengine.py without any Qt dependencies). But that could be a lot of code just to get to its ECDSA implementation. (you can probably strip out 90% of armoryengine.py, though, and keep just the ECDSA parts) Alternatively, you could extract my wrapper around Crypto++ and use that somehow. It does exactly what you want, and you can use publicly-verifiable download the crypto++ libraries, which have no external dependencies. (use only SecureBinaryData objects and all methods below this line). You lost me at secp256k1 ;-) If I install Armory on a machine, say without the Satoshi client, can I use it from a command line (or within Armory) to generate key pairs from passphrases? And if so what commands would I use? I don't see the option within Armory.
|
|
|
|
|