Bitcoin Forum
June 25, 2024, 05:32:32 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Re: Coldstorage and manually signing a trx from CLI (using OpenSSL) - solved  (Read 1022 times)
pebwindkraft (OP)
Sr. Member
****
Offline Offline

Activity: 257
Merit: 343


View Profile
July 03, 2016, 12:04:04 PM
Last edit: July 12, 2016, 02:09:37 PM by pebwindkraft
 #1

I want to further understand the signing process, especially when it comes to cold storage, so I built a set of shell scripts for OpenBSD/OSX/Linux.
I know about Armory, javascript libraries, ciyam, or other webpages for cold storage and signing… not the goal here.

Based on some old message by Pieter Wuille (September 29, 2012, "why OpenSSL?") here:
https://bitcointalk.org/index.php?topic=114064.0
--> "We use it for ECDSA signing and verification..."
I thought I’d use OPENSSL to sign and verify my code. (Is this still a valid approach?)

I created a raw trx, following the first 13 steps here:
http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx
and of course supported by
https://en.bitcoin.it/wiki/Protocol_specification#tx
Examination with the different offline tools shows the raw trx "looks ok". The raw trx produces the same sha256 hash as on the webpage.
Then I wanted to use "my own keys" to build a raw trx, and get it signed with OpenSSL. My unsigned raw trx would look like this:

010000000167cc10a3b7c5c52435770b6a1cb34a6a783803f028c42e95f9364d21e64b43c301000 0001976A9147A8911A06EF9A75A6CB6AF47D72A99A9B6ECB77988ACffffffff01EC8A0100000000 001976A9140DE4457D577BB45DEE513BB695BDFDC3B34D467D88AC00000000

To sign it, OPENSSL requires DER/PEM key for doing this at the command line. How to get them?
I used a (throw away) wallet, and dumped priv key. I converted the wif-c privkey via base58 conversion into hex.
On the public key:
in a shell script, I didn’t want to re-create the EC math to derive pubkey from privkey (maybe later, using bc and dc). So I looked up a previous trx (5a62b8697e33b59255ddab10b8f66ece0d5efec91c72134d07d90e03db61e051), what the hex code for the pubkey was… I appended this hex string with all the ASN1 fuzz, and then created via base64 conversion the OpenSSL PEM format. I verified the PEM file with "openssl asn1parse". And tested "openssl sign" with an example sha256.txt file. After signing, I "openssl verify"’d it. Result from openssl is "Signature Verified Successfully". So internally openssl "works" correctly, priv/pub key pair match (see the code below).
When I then assemble the trx and sign with OpenSSL, I get this:

010000000167cc10a3b7c5c52435770b6a1cb34a6a783803f028c42e95f9364d21e64b43c301000 0006A47304402206548cb4429b40f314711d46aa2e582b71041091f70064b276f2cbb800bb73d43 022011b6fe802a4f25dfe73a0c764add96011e43a02c41d2dd65164e2a4f0177ca8b01210293ccb 70fee4d33179c93bade0a9fefd62fde5ac53adc017649f513eec599509cffffffff01EC8A010000 0000001976A9140DE4457D577BB45DEE513BB695BDFDC3B34D467D88AC00000000

And when I try to broadcast via blockchain.info/de/pushtx, I get the message "Script resulted in a non-true stack: []".
Obviously OP_EQUALVERIFY and then OP_CHECKSIG don't get the expected result.
So I assume my OpenSSL key conversion is "somehow" wrong.  Huh Angry

I double checked the exactly same unsigned raw trx in bitcoin-QT, and tried to sign it manually in bitcoin-QT, and broadcasted successfully Smiley:

signrawtransaction '010000000167cc10a3b7c5c52435770b6a1cb34a6a783803f028c42e95f9364d21e64b43c301000 0001976A9147A8911A06EF9A75A6CB6AF47D72A99A9B6ECB77988ACffffffff01EC8A0100000000 001976A9140DE4457D577BB45DEE513BB695BDFDC3B34D467D88AC00000000'  '[{"txid":"c3434be6214d36f9952ec428f00338786a4ab31c6a0b773524c5c5b7a310cc67","vout":1,"scriptPubKey":"76A9147A8911A06EF9A75A6CB6AF47D72A99A9B6ECB77988AC"}]' ‚[„$my_privkey“]‘

{
  "hex": "010000000167cc10a3b7c5c52435770b6a1cb34a6a783803f028c42e95f9364d21e64b43c301000 0006a47304402203d15e12271521adb6e42c3f6a5eb5020883dd2042f23783e11385fb895fa1890 02200a84ba8e8055123abb22400b5dd90dbe670a1fa1cbbc206d5da59e54f4cc9c3501210293ccb 70fee4d33179c93bade0a9fefd62fde5ac53adc017649f513eec599509cffffffff01ec8a010000 0000001976a9140de4457d577bb45dee513bb695bdfdc3b34d467d88ac00000000",
  "complete": true
}

Any help appreciated…  Tongue


The code I use to assemble the PEM Key to sign with OpenSSL:

Code:
#!/bin/sh
# example keys from webpage:
hex_privkey=18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725
hex_pubkey=0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6
sha256_string=9302bda273a887cb40c13e02a50b4071a31fd3aae3ae04021b0b843dd61ad18e

# ASN1 structure fill-ups:
pre_string=$( echo "30740201010420" )
mid_string=$( echo "a00706052b8104000aa144034200" )

echo "use pre defined ASN.1 strings to concatenate PEM keyfile:"
echo "  a pre_string : $pre_string"
echo "  the privkey  : $hex_privkey"
echo "  a mid_string : $mid_string"
result=$( echo $hex_pubkey | cut -b 1-66 )
echo "  the pubkey   : $result"
result=$( echo $hex_pubkey | cut -b 67- )
echo "                   $result"

# assemble the hex key
result=$( echo $pre_string$hex_privkey$mid_string$hex_pubkey | sed 's/[[:xdigit:]]\{2\}/\\x&/g' )
printf "$result" > tmpfile

echo " "
echo "and base64 this file. PEM keyfiles also want some nice surroundings: "
result=$( base64 tmpfile )
echo "-----BEGIN EC PRIVATE KEY-----" > privkey.pem
echo $result | cut -b 1-64   >> privkey.pem
echo $result | cut -b 65-128 >> privkey.pem
echo $result | cut -b 129-   >> privkey.pem
echo "-----END EC PRIVATE KEY-----" >> privkey.pem
cat privkey.pem

echo " "
echo "corresponding pubkey.pem (openssl ec -in privkey.pem -pubout -out pubkey.pem)"
openssl ec -in privkey.pem -pubout -out pubkey.pem > /dev/null 2>&1
cat pubkey.pem

echo " "
echo "verifying the signing process with test data (openssl asn1parse -in privkey.pem)"
echo $sha256_string > sha256.txt
openssl asn1parse -in privkey.pem
echo "-->openssl pkeyutl -sign -in sha256.txt -inkey privkey.pem -keyform PEM > privkey_pem.sig"
openssl pkeyutl -sign -in sha256.txt -inkey privkey.pem -keyform PEM > privkey_pem.sig
echo "-->openssl pkeyutl -verify -in sha256.txt -inkey privkey.pem -sigfile privkey_pem.sig"
openssl pkeyutl -verify -in sha256.txt -inkey privkey.pem -sigfile privkey_pem.sig
echo " "
pebwindkraft (OP)
Sr. Member
****
Offline Offline

Activity: 257
Merit: 343


View Profile
July 12, 2016, 02:08:25 PM
 #2

Hi,

The main issue is to understand, how to come from hex to PEM keys, to be able to sign offline with openssl from the shell. With some support over here I got it working:

http://bitcoin.stackexchange.com/questions/46455/verifying-a-bitcoin-trx-on-the-unix-cmd-line-with-openssl

The second thing to remember is to always work on binary/raw data, and not hex representation of data. And maybe third, understanding the double hashing with sha256.

I have then created a raw transaction, following the 19 steps logic from here:

http://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx

Then I used openssl as decribed before, to verify the trx. It finally gave me a transaction, that I could copy and paste into https://blockchain.info/de/pushtx.

I haven't had any error checking code implemented (yet), so every now and then I got an „S-value to high error“. Per specs, an s value greater than N/2 is not allowed (N is the curve order). Also I had not added strict DER checking. This is work in progress.

Happy cold wallet user now  Grin
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!