PEM-Format für ECDSA

Ich habe mir die API-Dokumentation von Coinapult angesehen, in der die Verwendung des PEM-Formats in python-ecdsa beschrieben wird . Insbesondere private Schlüssel und öffentliche Schlüssel müssen mit PEM formatiert werden.

Nehmen wir den angegebenen öffentlichen Schlüssel von Coinapult:

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWp9wd4EuLhIZNaoUgZxQztSjrbqgTT0w
LBq8RwigNE6nOOXFEoGCjGfekugjrHWHUi8ms7bcfrowpaJKqMfZXg==
-----END PUBLIC KEY-----

Verwenden von python-ecdsa:

vk = ecdsa.VerifyingKey.from_pem(ECC_COINAPULT_PUB)
s = vk.to_string()
s.encode('hex')   
>>> "5a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e"

Oder wenn es ein öffentlicher Bitcoin-Schlüssel wäre, wäre das045a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e

OK, das macht Sinn, aber wenn wir die base64-codierten Daten zwischen dem führenden und dem nachfolgenden nehmen -----BEGIN-----:

base64_data = "".join(ECC_COINAPULT_PUB[27:-26 ].split('\n'))
s = base64.b64decode(base64_data)
result = s.encode("hex")
>>> "3056301006072a8648ce3d020106052b8104000a034200045a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e"  # WTF is this??

Beachten Sie, dass das PEM-Format in eine Art DER-String dekodiert wird 3056301006072a8648ce3d020106052b8104000a034200045a9f7077812e2e121935aa14819c50ced4a3adbaa04d3d302c1abc4708a0344ea738e5c51281828c67de92e823ac7587522f26b3b6dc7eba30a5a24aa8c7d95e, aber was um alles in der Welt ist dieser DER-String? Wie ich sehe 5a9f7077....a8c7d95e, ist in dieser Zeichenfolge, also was bedeuten die führenden Bytes?

Fragen : 1. Wie codiere ich einen Pubkey in das PEM-Format , ohne Python-ECDSA zu verwenden ? 2. Ist es das gleiche Verfahren in #1 für private Schlüssel wie für öffentliche Schlüssel?

Antworten (1)

#0 Was ist das Format? Wie Sie teilweise erraten haben, handelt es sich dabei um die „PEM“-Panzerung der DER-Codierung des SubjectPublicKeyInfoASN.1-Typs von X.509 , neu veröffentlicht für die Verwendung im Internet als RFC5280-Abschnitt 4.1, insbesondere 4.1.2.7 . Um in Zukunft mehrere Algorithmen, einschließlich neuer, zu unterstützen, ist diese Struktur eine SEQUENCEvon an AlgorithmIdentifier, die den Algorithmus identifiziert (unter Verwendung von OBJECT IDENTIFIERfür den Algorithmus und verschiedene Arten von Parametern, abhängig vom Algorithmus), gefolgt von einer BIT STRING, die den in einem Format codierten Schlüsselwert enthält das variiert je nach Algorithmus. Die für ECDSA (und ECDH) spezifische AlgId und das Schlüsselformat befinden sich in Abschnitt 2.3.5 von RFC3279, obwohl Sie die komplizierten Teile darüber ignorieren könnenECParametersweil in der Praxis jeder die einfachere namedCurve OBJECT IDENTIFIEROption verwendet und das Schlüsselformat nur der Punkt SEC1/X9.62 ist.

Hier 301006072a8648ce3d020106052b8104000aist die AlgId und dekodiert als

    0:d=0  hl=2 l=  16 cons: SEQUENCE
    2:d=1  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   11:d=1  hl=2 l=   5 prim: OBJECT            :secp256k1

(Wie Sie bereits herausgefunden haben, ist "PEM" nur base64 des DER, mit Zeilenumbrüchen in Intervallen sowie einer ----BEGIN whatever-----Zeile oben und einer -----END whatever-----Zeile unten.)

#1 codieren ohne Python? Abgesehen davon, dass Sie (einen Teil von) DER selbst implementieren, was nicht so schwierig ist, wenn Sie möchten, sehe ich, dass die Seite, auf die Sie verlinken, viel über OpenSSL-Kompatibilität spricht: für Programme in C oder Sprachen, die C (einfach) aufrufen können ist viele, OpenSSL kann ECC-Schlüssel in diesem Format (und der ungepanzerten DER-Form) generieren, lesen, schreiben und für verschiedene Operationen verwenden. Java 7+-Kryptographie kann es, aber die Standardanbieter nur in DER; für PEM müssen Sie selbst en/de-armor oder http://www.BouncyCastle.org verwendenstattdessen. Ich gehe davon aus, dass dot-NET das kann, aber ich verwende das nicht und kann es nicht definitiv sagen. Ich weiß, ich habe Perl-Module für DER gesehen, aber irgendwie kann ich nie etwas in CPAN finden, obwohl das sein Zweck ist. Wenn Sie eine spezifischere Antwort wünschen, überarbeiten Sie Ihre Frage (oder stellen Sie eine neue, wenn sie sich ausreichend unterscheidet).

#2 privater Schlüssel? Diese Seite sagt, dass sie -----BEGIN EC PRIVATE KEY-----eines von zwei "alten" Formaten in OpenSSL verwendet: unverschlüsselt oder verschlüsselt. Da die Beispiele kein Passwort zeigen, gehe ich von Ersterem aus. Wenn Sie sich eine Schlüsseldatei ansehen und Zeilen über Proc-typeund DEK-infoeingefügt nach der -----BEGINZeile, aber vor den base64-Daten sehen, ist sie Legacy-verschlüsselt und das ist komplizierter.

Ohne das ist es die im SEC1-Dokument unter http://www.secg.org/ in C.4 definierte Struktur des privaten Schlüssels, die einen OCTET STRINGfür den privaten Schlüssel (eigentlich eine ganze Zahl, aber nicht als solche codiert) definierten Parameter enthält in C.2, die bei genauer Betrachtung im Wesentlichen denen in RFC 3279 entsprechen, und wieder ein BIT STRING, das den öffentlichen Schlüssel enthält (ein Punkt).

OpenSSL unterstützt auch das "neue" (ab etwa 2000!) PKCS#8-Format für private Schlüssel. Ähnlich wie X.509 SPKI für den öffentlichen Schlüssel ist dies ein generischer Wrapper, der im Grunde genommen AlgorithmIdentifierfür den Algorithmus plus OCTET STRINGden Schlüsselwert je nach Algorithmus enthält, außer dass PKCS#8 auch eine Option zum Verschlüsseln auf PKCS#8-Ebene hat (im Gegensatz zum "PEM"-Level). Ich weiß nicht, ob das Python-Modul diese Formate verarbeitet oder nicht, und wenn nicht, ob Sie sie verwenden möchten und dadurch nicht mit dem Python-Modul kompatibel sind. Wenn Sie PKCS#8 nicht und OpenSSL verwenden möchten, achten Sie darauf, die spezifischen EC-Routinen und nicht die generischen zu verwenden.

Vielen Dank! Irgendwann habe ich es herausgefunden: der_string = "\x30{totallen}\x02\x01\x01\x04\x20{privkey}\xa0\x07\x06\x05\x2b\x81\x04\x00\x0a\xa1\x44\x03\x42\x00\x04{x}{y}"ist für Privkeys und der_string = "\x30{totallen}\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04\x00\x0a\x03\x42\x00\x04{pubkey}"für Pubkeys
Danke, das bringt viel Licht ins Dunkel! Nur eine Frage: Wird der öffentliche Bitcoin-Schlüssel überhaupt im Nachrichtensignierungsprozess benötigt, wenn DER-codierte PEM-Dateien zum Signieren der Nachricht verwendet werden?
@Kebman: Für die ECDSA-Signierung ist nur ein privater Schlüssel erforderlich, nicht öffentlich. Aber Bitcoin signiert keine Nachrichten, es signiert Transaktionen, die (immer oder fast) Adressen beinhalten, die aus den öffentlichen Schlüsseln gehasht werden. Von OpenSSL erstellte EC-Privatschlüsseldateien enthalten immer den öffentlichen Schlüssel, obwohl dies von SEC1 (und PKCS8) nicht erforderlich ist, und in jedem Fall kann der öffentliche Schlüssel immer aus dem privaten Schlüssel neu berechnet werden.