Verifizieren eines Bitcoin-TRX auf der Unix-cmd-Zeile mit OpenSSL?

Ich möchte openssl auf Unixoide-Systemen verwenden, um eine Transaktion zu überprüfen. Ich trete auf Fehler, wenn ich versuche, den Hash eines Bitcoin-Trx zu verifizieren. Hier arbeite ich an Mac OSX und OpenSSL (1.0.2a 19. März 2015).

Ich weiß, dass ich den QT-Client oder die verschiedenen Python/PHP/Java-Lösungen verwenden kann, das ist hier nicht das Ziel. Ich verstehe auch, dass Bitcoin nach libsecp256k1 wandert… Ich bin dem Beispiel von Pizza trx hier gefolgt:

Wie funktioniert der ECDSA-Verifizierungsalgorithmus während der Transaktion?

Für die Verifizierung ist kein privater Schlüssel erforderlich, nur Pubkey, Hash und Sig. Openssl bietet zwei Möglichkeiten, ein Ergebnis zu überprüfen:

openssl dgst -sha256 -verify pubkey.pem -signature tmpfile.sig sha256.txt

oder

openssl pkeyutl -verify -pubin -inkey pubkey.pem -sigfile tmpfile.sig -in sha256.txt

Knifflig ist, wie man vom Hex-Pub-Key („042e930f39…ebcabb“) in das PEM-Format kommt, das openssl zur Verifizierung will. Am Ende habe ich die Schritte hinzugefügt, wie ich den Inbusschlüssel in PEM umgewandelt habe.

Wenn ich das bitocin double sha256 des erwähnten Pizza trx verwende (ich habe auch mehrere andere ausprobiert), erhalte ich diesen Fehler:

openssl dgst -sha256 -verify pubkey.pem -signature tmpfile.sig sha256.txt
      Error Verifying Data
      140735175988048:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1198:
      140735175988048:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:372:Type=ECDSA_SIG

oder mit pkeyutl:

openssl pkeyutl -verify -pubin -inkey pubkey.pem -sigfile tmpfile.sig -in sha256.txt
      Public Key operation error
      140735175988048:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1198:
      140735175988048:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:372:Type=ECDSA_SIG

Wenn ich meine priv- und pub-Schlüssel mit openssl erstelle und einen „demo sha256“-String signiere, kann ich das korrekt verifizieren. Nur diese Bitcoin sha256s-Strings funktionieren nicht. Irgendetwas muss mir fehlen…

ERSTELLEN der PEM-Datei:

Basierend auf mehreren Messwerten hier im Stackexchange habe ich die PEM-Schlüssel von openssl rückentwickelt. Der pem-formatierte Schlüssel will einen PEM_prestring („3056301006072a8648ce3d020106052b8104000a034200“) und den angehängten Pubkey.

$ result=3056301006072a8648ce3d020106052b8104000a034200042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb
$ result=$( echo $result | sed 's/[[:xdigit:]]\{2\}/\\x&/g' )
$ printf $result > tmpfile
$ hexdump -C tmpfile
00000000  30 56 30 10 06 07 2a 86  48 ce 3d 02 01 06 05 2b  |0V0...*.H.=....+|
00000010  81 04 00 0a 03 42 00 04  2e 93 0f 39 ba 62 c6 53  |.....B.....9.b.S|
00000020  4e e9 8e d2 0c a9 89 59  d3 4a a9 e0 57 cd a0 1c  |N......Y.J..W...|
00000030  fd 42 2c 6b ab 36 67 b7  64 26 52 93 82 c2 3f 42  |.B,k.6g.d&R...?B|
00000040  b9 b0 8d 78 32 d4 fe e1  d6 b4 37 a8 52 6e 59 66  |...x2.....7.RnYf|
00000050  7c e9 c4 e9 dc eb ca bb                           ||.......|

Dies wird base64-kodiert sein und einige schöne Umgebungen hinzugefügt.

$ openssl enc -base64 -in tmpfile -out pubkey.pem
$ cat pubkey.pem 
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELpMPObpixlNO6Y7SDKmJWdNKqeBXzaAc
/UIsa6s2Z7dkJlKTgsI/QrmwjXgy1P7h1rQ3qFJuWWZ86cTp3OvKuw==

und wir geben pubkey.pem eine schöne Umgebung, damit es so aussieht:

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELpMPObpixlNO6Y7SDKmJWdNKqeBXzaAc
/UIsa6s2Z7dkJlKTgsI/QrmwjXgy1P7h1rQ3qFJuWWZ86cTp3OvKuw==
-----END PUBLIC KEY-----

und überprüfen Sie über asn die Struktur:

$ openssl asn1parse -in pubkey.pem 
    0:d=0  hl=2 l=  86 cons: SEQUENCE
    2:d=1  hl=2 l=  16 cons: SEQUENCE
    4:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   13:d=2  hl=2 l=   5 prim: OBJECT            :secp256k1
   20:d=1  hl=2 l=  66 prim: BIT STRING

Die von mir verwendeten Dateien:

$ cat pubkey.pem  
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELpMPObpixlNO6Y7SDKmJWdNKqeBXzaAc
/UIsa6s2Z7dkJlKTgsI/QrmwjXgy1P7h1rQ3qFJuWWZ86cTp3OvKuw==
-----END PUBLIC KEY-----

$ cat tmpfile.sig
30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e

$ cat sha256.txt
692678553d1b85ccf87d4d4443095f276cdf600f2bb7dd44f6effbd7458fd4c2

Antworten (1)

Sie haben den Pubkey richtig verstanden, aber mindestens eine Sache falsch und vielleicht mehr in den Teilen, die Sie nicht gezeigt haben.

Erstens und grundlegend verwendet Bitcoin ein unkonventionelles (wohl nicht standardisiertes) Schema, bei dem die Daten vor der NonceG,kinv(Hash+Nonceimage)-Berechnung und der entsprechenden Überprüfung doppelt gehasht werden. dgst -sign/-verifytut nur den Standard-Single-Hash, also müssen Sie entweder zuerst hashen und dann verwenden dgst -sign/verifyoder zweimal hashen und dann verwenden pkeyutl -sign/verify.

Auch die Signaturdatei, die Verifizierungseingabedatei (Hash oder andere) und die Hash-Eingabe(n) müssen Rohdaten, auch Binärdaten , sein , nicht die Hex-Darstellung.

Daher:

$ cat pizza.inphex
01000000018dd4f5fbd5e980fc02f35c6ce145935b11e284605bf599a13c6d41
5db55d07a1000000001976a91446af3fb481837fadbb421727f9959c2d32a368
2988acffffffff0200719a81860000001976a914df1bd49a6c9e34dfa8631f2c
54cf39986027501b88ac009f0a5362000000434104cd5e9726e6afeae357b180
6be25a4c3d3811775835d235417ea746b7db9eeab33cf01674b944c64561ce33
88fa1abd0fa88b06c44ce81e2234aa70fe578d455dac0000000001000000
$ xxd -r -p <pizza.inphex >pizza.inpraw
$ cat pizza.sighex
30450221009908144ca6539e09512b9295c8a27050d478fbb96f8addbc3d075544dc41328702201aa528be2b907d316d2da068dd9eb1e23243d97e444d59290d2fddf25269ee0e
$ xxd -r -p <pizza.sighex >pizza.sigraw
$ cat pizza.keyhex
3056301006072a8648ce3d020106052b8104000a034200
042e930f39ba62c6534ee98ed20ca98959d34aa9e057cda01cfd422c6bab3667b76426529382c23f42b9b08d7832d4fee1d6b437a8526e59667ce9c4e9dcebcabb
$ xxd -r -p <pizza.keyhex | openssl pkey -pubin -inform der >pizza.keypem

$ openssl sha256 <pizza.inpraw -binary >pizza.hash1; xxd pizza.hash1
0000000: 0838 6747 8cb0 d1d8 bb86 4175 bbc4 9728  .8gG......Au...(
0000010: cffc c114 bc2e 762c 6df6 4f2c 965a 9a66  ......v,m.O,.Z.f
$ openssl sha256 <pizza.hash1 -verify pizza.keypem -signature pizza.sigraw
Verified OK

$ openssl sha256 <pizza.hash1 -binary >pizza.hash2; xxd pizza.hash2
0000000: c2d4 8f45 d7fb eff6 44dd b72b 0f60 df6c  ...E....D..+.`.l
0000010: 275f 0943 444d 7df8 cc85 1b3d 5578 2669  '_.CDM}....=Ux&i
$ openssl pkeyutl <pizza.hash2 -verify -pubin -inkey pizza.keypem -sigfile pizza.sigraw
Signature Verified Successfully

Beachten Sie, dass der zweite Hash der in #32305 Punkt 4 gezeigte ist, außer dass die Software von amaclin die Bytes in umgekehrter Reihenfolge anzeigt.

thx Dave, präzise, ​​knackig und klar. Die Hex-Darstellung und die Rohdaten waren der verwirrende Teil. thx, grds, Volker
Hallo, beim Konvertieren von pizza.keyhex in pizza.keypem erhalte ich die Fehlermeldung "Public Key kann nicht geladen werden". Warum ist das so? Ich habe genau die gleichen Befehle befolgt wie du.
@ user2298995: Ich weiß es nicht; Es sollte funktionieren und ist nicht sehr kompliziert. Stellen Sie sicher, dass Sie die Daten genau richtig haben – haben Sie ganz nach rechts gescrollt? Stellen Sie sicher, dass Ihr xxd funktioniert: Legen Sie die Ausgabe in eine Datei und untersuchen Sie sie, versuchen Sie dann, diese Datei (anstatt zu pipen) mit zu lesen, pkey -inform der -pubinund wenn dies fehlschlägt, mit asn1parse -inform der.