Pages:
Author

Topic: Zsh/OpenSSL Shell Script Key Generator (Read 5513 times)

sr. member
Activity: 252
Merit: 250
April 24, 2013, 04:28:33 PM
#21

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.


+100 It's a must! Thanks!

If your Linux box stumbles on "tail -r", substitute by "tac" (thanks to mintymark).
member
Activity: 93
Merit: 10
April 23, 2013, 07:52:18 PM
#20
The predecessor to Armory (PyBtcEngine) used pure-python implementation of ECDSA.  This implementation was created by forum user "Lis" here:

https://bitcointalksearch.org/topic/solved-python-secp256k1-23241

If 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 Smiley)

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.
sr. member
Activity: 293
Merit: 250
January 31, 2013, 05:25:48 AM
#19
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.pdf

Live 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.
legendary
Activity: 1288
Merit: 1080
January 07, 2013, 10:09:25 PM
#18

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:

Code:
checksum() {
    perl -we "print pack 'H*', '$1'" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -binary |
    perl -we "print unpack 'H8', join '', <>"
}
pc
sr. member
Activity: 253
Merit: 250
January 07, 2013, 10:01:42 PM
#17
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.
Code:
#!/bin/zsh
zparseopts h=help v=verbose c=compressed t=testnet
if [[ -n $help ]]; then
<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
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
December 30, 2012, 02:22:26 PM
#16
The predecessor to Armory (PyBtcEngine) used pure-python implementation of ECDSA.  This implementation was created by forum user "Lis" here:

https://bitcointalksearch.org/topic/solved-python-secp256k1-23241

If 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 Smiley)

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).
sr. member
Activity: 286
Merit: 251
December 30, 2012, 09:36:36 AM
#15
To get this to work with Ubuntu, I had to change tail -r to tac.

Both reverse the order of lines in a file.
hero member
Activity: 784
Merit: 1009
firstbits:1MinerQ
December 30, 2012, 02:20:49 AM
#14
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://bitcointalksearch.org/topic/m.1425723

Generate keys from the cmd line, from random data,

hexdump -v -e '/1 "%02X"' -n 32 /dev/urandom | keyfmt '%a:%w'
legendary
Activity: 1708
Merit: 1066
December 27, 2012, 03:27:12 AM
#13
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%20keys

The OpenSSL commands to encrypt and decrypt the private key export file are near the bottom of the wiki.
legendary
Activity: 1792
Merit: 1008
/dev/null
December 27, 2012, 02:48:45 AM
#12
How would I go about determining what the associated public key is?

Can I use the openssl command? Something like:

Quote
echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}

Damn, this is exactly what I've been trying to figure out all day as well Smiley 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
legendary
Activity: 3514
Merit: 4895
December 27, 2012, 12:50:03 AM
#11
How would I go about determining what the associated public key is?

Can I use the openssl command? Something like:

Quote
echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}

Damn, this is exactly what I've been trying to figure out all day as well Smiley 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
legendary
Activity: 1792
Merit: 1008
/dev/null
December 27, 2012, 12:37:37 AM
#10
How would I go about determining what the associated public key is?

Can I use the openssl command? Something like:

Quote
echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}

Damn, this is exactly what I've been trying to figure out all day as well Smiley 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!
legendary
Activity: 3514
Merit: 4895
December 26, 2012, 10:56:38 PM
#9
How would I go about determining what the associated public key is?

Can I use the openssl command? Something like:

Quote
echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}

Damn, this is exactly what I've been trying to figure out all day as well Smiley 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?
legendary
Activity: 1792
Merit: 1008
/dev/null
December 26, 2012, 10:35:59 PM
#8
How would I go about determining what the associated public key is?

Can I use the openssl command? Something like:

Quote
echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}

Damn, this is exactly what I've been trying to figure out all day as well Smiley No luck here either.
openssl dosnt support this.
legendary
Activity: 3514
Merit: 4895
December 26, 2012, 09:14:12 PM
#7
. . . I suspect you'll need an actual expert here.
And here I was hoping you were that "actual expert"  Grin

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.
pc
sr. member
Activity: 253
Merit: 250
December 26, 2012, 09:09:12 PM
#6
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.
legendary
Activity: 3514
Merit: 4895
December 26, 2012, 08:39:35 PM
#5
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:

Quote
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:

Quote
echo -n C4BBCB1FBEC99D65BF59D85C8CB62EE2DB963F0FE106F483D9AFA73BD4E39A8A |openssl {some parameters here}
legendary
Activity: 3514
Merit: 4895
December 26, 2012, 10:10:58 AM
#4
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!
pc
sr. member
Activity: 253
Merit: 250
December 24, 2012, 10:19:38 PM
#3
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.
legendary
Activity: 1792
Merit: 1008
/dev/null
December 24, 2012, 10:12:36 PM
#2
2. how about making a POSIX version? (runs on every *nix, atleast it should)
Pages:
Jump to: