Ich weiß, es ist alt, aber ich habe in letzter Zeit versucht, dieselbe Frage zu klären, also hier eine Art Antwort.
Nehmen wir an, Sie haben so eine Signatur erstellt:
$ openssl dgst -sha256 -sign private_secp160k1.pem foo.txt > sign.bin
Da die Kurve 160 Bit beträgt, besteht die Signatur aus zwei 20-Byte-Nummern. Standardmäßig wird es von OpenSSL im binären DER-Format von ASN.1 geschrieben. Bei der Prüfung sollten wir mindestens 2 * 20 Bytes finden:
$ xxd -i < sign.bin 0x30, 0x2d, 0x02, 0x14, 0x22, 0xd0, 0x8b, 0xc1, 0x0d, 0x0b, 0x7b, 0xff, 0xe6, 0xc1, 0x77, 0xc1, 0xdc, 0xc4, 0x2f, 0x64, 0x05, 0x17, 0x71, 0xc8, 0x02, 0x15, 0x00, 0xdd, 0xf4, 0x67, 0x10, 0x39, 0x92, 0x1b, 0x13, 0xf2, 0x40, 0x20, 0xcd, 0x15, 0xe7, 0x6a, 0x63, 0x0b, 0x86, 0x07, 0xb6
In dieser bestimmten DER-codierten Signatur sind 47 Byte enthalten. Eine mit DER oder PEM codierte Signatur kann mit dem asn1parse
Befehl von OpenSSL untersucht werden, um herauszufinden, was die Bytes sind:
$ openssl asn1parse -inform DER -in sign.bin 0:d=0 hl=2 l= 45 cons: SEQUENCE 2:d=1 hl=2 l= 20 prim: INTEGER :22D08BC10D0B7BFFE6C177C1DCC42F64051771C8 24:d=1 hl=2 l= 21 prim: INTEGER :DDF4671039921B13F24020CD15E76A630B8607B6
Kurz gesagt heißt es:
- Bei Byte 0 gibt es einen DER-Header der Länge 2, der eine Folge von Elementen mit einer Gesamtlänge von 45 Bytes anzeigt.
- Bei Byte 2 gibt es einen DER-Header der Länge 2, der ein INTEGER-Element der Länge 20 anzeigt. Das erste Element der SEQUENCE (20 Bytes werden dann in Hex gedruckt)
- Bei Byte 24 gibt es einen DER-Header der Länge 2, der ein INTEGER-Element der Länge 21 angibt, das zweite Element der SEQUENCE (20 Bytes werden dann in Hex dargestellt).
(Das d = N bedeutet nur "Tiefe", daher haben die beiden INTEGER-Elemente d == 1, da sie Teil einer Sequenz sind.)
Schön die rohen Bytes von früher drucken, erkennt man die Elemente:
$ xxd -i < sign.bin 0x30, 0x2d, # Sequence of length 45 to follow (45 == 0x2d) 0x02, 0x14, # Integer of length 20 to follow (20 == 0x14) # Here come the 20 bytes: 0x22, 0xd0, 0x8b, 0xc1, 0x0d, 0x0b, 0x7b, 0xff, 0xe6, 0xc1, 0x77, 0xc1, 0xdc, 0xc4, 0x2f, 0x64, 0x05, 0x17, 0x71, 0xc8, 0x02, 0x15, # Integer of length 21 to follow (21 == 0x15) 0x00, # The first of the 21 integer bytes (see explanation below!) # Here come the remaining 20 bytes 0xdd, 0xf4, 0x67, 0x10, 0x39, 0x92, 0x1b, 0x13, 0xf2, 0x40, 0x20, 0xcd, 0x15, 0xe7, 0x6a, 0x63, 0x0b, 0x86, 0x07, 0xb6
Warum ist also die zweite ganze Zahl 21 Bytes?
Integer in DER sind Zweierkomplement, wenn also das erste Byte der 20-Byte-Ganzzahl> 0x7F ist, wird ein zusätzliches 0x00-Byte vorangestellt, dh das erste Bit ist immer 0. Mit anderen Worten, während R und S 20-Byte-Zahlen sind, Die Kodierung in DER-Ganzzahlen kann ein zusätzliches Byte erfordern.
In OpenSSL enthält der Typ ECDSA_SIG zwei BIGNUMs. Sobald Sie die DER-Bytes mit entschlüsselt haben d2i_ECDSA_SIG
, können Sie mit yourSig->r
und auf sie zugreifen. yourSig->s
Dies ist <= 20 Bytes (für 160-Bit-Kurven).
Es ist auch möglich, dass R oder S weniger als 20 Bytes benötigen, wenn ihre ersten höchstwertigen Ziffern gleich Null sind. Sie können die für jedes Byte benötigte Anzahl von Bytes ermitteln BN_num_bytes
und dann in ein reguläres BN_bn2bin
Bytearray mit serialisieren.
ECDSA_SIG* ecSig = d2i_ECDSA_SIG(NULL, derBuf, derBufSize); int rBytes = BN_num_bytes(ecSig->r), // Number of bytes needed for R sBytes = BN_num_bytes(ecSig->s); // Number of bytes needed for S // ... unsigned char someBuffer[40] = ; BN_bn2bin( ecSig->r, someBuffer + 20 - rBytes ); // Place R first in the buffer BN_bn2bin( ecSig->s, someBuffer + 40 - sBytes ); // Place S last in the buffer
Auf der Empfängerseite würden Sie dann einfach die ECDSA_SIG-Instanz neu erstellen, indem Sie its r
und member setzen s
:
ECDSA_SIG* ecSig = ECDSA_SIG_new(); BN_bin2bn( someBuffer, 20, ecSig->r ); BN_bin2bn( someBuffer + 20, 20, ecSig->s );