2017-12-12 31 views
0

Ich brauche Hilfe, wie man Java Private.pem richtig konstruiert. Ich habe eine ECDSA PEM-Datei in Java und eine in Python erstellt. Ich habe die richtige Python-Implementierung, aber die Java-Version ist nicht korrekt.PEM-Kodierung von ECDSA in Java

KeyPair pair = GenerateKeys(); 
PrivateKey priv = pair.getPrivate(); 
PublicKey pub = pair.getPublic(); 

// Convert to Bytes then Hex for new account params 
byte[] bytePriv = priv.getEncoded(); 
byte[] bytePub = pub.getEncoded(); 

// save keys 
SaveKeyToFile(bytePriv, "private", "private"); 

// Calls this function 
public static void SaveKeyToFile(byte[] Key, String filename, String keyType) throws IOException, NoSuchAlgorithmException, NoSuchAlgorithmException, InvalidKeySpecException { 
    StringWriter stringWriter = new StringWriter(); 
    PemWriter pemWriter = new PemWriter(stringWriter); 
    PemObjectGenerator pemObject = new PemObject("EC " + keyType.toUpperCase() + " KEY", Key); 


    pemWriter.flush(); 
    pemWriter.close(); 
    String privateKeyString = stringWriter.toString(); 
    FileUtils.writeStringToFile(new File(filename + ".pem"), privateKeyString); 
} 

Für die ASN1 beide mit OpenSSL von Java und Python analysieren (Ist nicht hexdump wegen seiner Länge umfassen):

JAVA 
0:d=0 hl=3 l= 141 cons: SEQUENCE   
3:d=1 hl=2 l= 1 prim: INTEGER   :00 
6:d=1 hl=2 l= 16 cons: SEQUENCE   
8:d=2 hl=2 l= 7 prim: OBJECT   :id-ecPublicKey 
17:d=2 hl=2 l= 5 prim: OBJECT   :secp256k1 
24:d=1 hl=2 l= 118 prim: OCTET STRING  [HEXDUMP] 

PYTHON 
0:d=0 hl=2 l= 116 cons: SEQUENCE   
2:d=1 hl=2 l= 1 prim: INTEGER   :01 
5:d=1 hl=2 l= 32 prim: OCTET STRING  [HEXDUMP] 
39:d=1 hl=2 l= 7 cons: cont [ 0 ]   
41:d=2 hl=2 l= 5 prim: OBJECT   :secp256k1 
48:d=1 hl=2 l= 68 cons: cont [ 1 ]   
50:d=2 hl=2 l= 66 prim: BIT STRING  

Wie für die Ausgabe PEM:

Java: 
-----BEGIN EC PRIVATE KEY----- 
MIGNAgEAMBAGByqGSM49AgEGBSuBBAAKBHYwdAIBAQQgiEc2TOzXj4mrUisuv+0p 
xZ/z+Z/VyIvWug17zjNOPIKgBwYFK4EEAAqhRANCAATWi28vsiZdfqbqodDZc1uz 
UFwNcu90l2ezayH0L4ZYB+MfReMCBFG/P6kn12GLj3DipqmvRucgmOlFVmggm+nH 
-----END EC PRIVATE KEY----- 

Python: 
-----BEGIN EC PRIVATE KEY----- 
MHQCAQEEINTaEQvUvtOQlanp0lWv0KBcSs8IltKYH26OkoNxLQc5oAcGBSuBBAAK 
oUQDQgAEcp3sseSpAXzIzWCwswYnsVnIZ0EEtkXl/CJWChQHilWLwWsxGq11/g/6 
38UfZbsjE5TSf6zT8VXvTZE++u9c+A== 
-----END EC PRIVATE KEY----- 

Hilfe wäre sehr willkommen!

+0

JCE ' PrivateKey.getEncoded() 'gibt unverschlüsselte PKCS8-Codierung zurück; der richtige PEM-Typ dafür ist 'BEGIN/END PRIVATE KEY' (ohne spezifischen Algorithmus wie 'EC') und dann OpenSSL und mit OpenSSL kompatible Dinge werden es lesen. Wenn Sie die "traditionelle" Algorithmus-spezifische Form von OpenSSL brauchen, die härter ist, aber meistens ein Betrogener; Ich muss jetzt gehen, aber kann das später bei Bedarf ausfüllen. PS: EC-Schlüssel/keyparis sind für ECDSA _usable_, aber nicht darauf beschränkt. Ein _cert_ OTOH kann durch KeyUsage begrenzt werden. –

+0

Danke für die Info. Die Java-Pem-Ausgabe muss dieser Spezifikation entsprechen: https://tools.ietf.org/html/rfc5915. Es soll EC PRIVATE KEY haben. Beide Schlüssel enthalten die secp256k1-Kurve. Der Hex-Dump ist länger auf dem Java-1 und die Ganzzahl ist 0 statt 1. Nicht ganz sicher, wie Sie in die Details gelangen, um es zu korrigieren.Ich experimentiere gerade mit MiscPEMGenerator, um zu sehen, ob es mir hilft, die richtige Ausgabe zu erreichen. – dtseng

+0

hast du wirklich die Koblitz-Kurve vor? Normalerweise wollen Leute secp256r1 (beachte das 'r'), da das das ist, das NIST P-256 – lockcmpxchg8b

Antwort

2

(Sorry für die Verspätung.)

Okay, tun Sie den Algorithmus-spezifische Form benötigen aber JCE PrivateKey.getEncoded() gibt die PKCS8 (Griffe alle Algorithmen) Kodierung, die meist die gleichen Q wie How can I convert a .p12 to a .pem containing an unencrypted PKCS#1 private key block? ist außer Sie ECC wollen anstatt RSA und (wichtiger) verwenden Sie Java mit BouncyCastle.

So, Ihre Optionen sind:

  • schreiben die PKCS8 Codierung, entweder in PEM oder direkt in binären (DIE), und verwenden Sie openssl ec oder in 1.1.0 openssl pkey -traditional es den Algorithmus spezifische zu konvertieren PEM-Form, die SEC1 ist (RFC5915 ist im Grunde eine Wiederveröffentlichung von SEC1).

  • Schreiben Sie die PKCS8-Codierung (entweder PEM oder DER) und verwenden Sie openssl asn1parse -strparse, um den algorithmenspezifischen Teil zu extrahieren oder den Offset des algorithmenspezifischen Teils zu ermitteln und direkt zu extrahieren. Ein 256-Bit-ECC-Schlüsselpaar DER codiert hauptsächlich mit Einzel-Oktett-Längen, aber die OID, die die (benannte) Kurve identifiziert, kann in der Größe für unterschiedliche Kurven variieren; Wie Ihr Beispiel zeigt, ist es 24 + 2 für secp256k1, also können Sie einfach Arrays.copyOfRange(Key,26,Key.length) zu Ihrer aktuellen Logik geben. Für ECC-Schlüsselpaare, die größer als 256 Bits sind, muss die DER-Codierung möglicherweise variieren, und die Grenzlinie kann davon abhängen, ob der öffentliche Wert im Schlüsselpaar in unkomprimierter oder komprimierter Form vorliegt, was Sie praktisch nicht steuern können (JCE bietet keine Optionen innerhalb einer Codierung). In diesem Fall müssten mindestens einige DER manuell verarbeitet werden. In diesem Fall würde ich stattdessen zur nächsten Option gehen.

  • BC, die Sie bereits verwenden, macht die Fähigkeit PKCS8 Strukturen zu manipulieren, und das kann man verwenden, um die Algorithmus-spezifische SEC1 Codierung zu extrahieren, so etwas wie dieses:

 
    import org.bouncycastle.asn1.ASN1Object; 
    import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 
    import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; // as defined by PKCS8 
    ... 
    PrivateKey k = /* whatever */; 
    PemWriter w = new PemWriter (/* underlying writer */); 
    PrivateKeyInfo i = PrivateKeyInfo.getInstance(ASN1Sequence.getInstance(k.getEncoded())); 
    if(! i.getPrivateKeyAlgorithm().getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)){ 
     throw new Exception ("not EC key"); 
    } 
    ASN1Object o = (ASN1Object) i.parsePrivateKey(); 
    w.writeObject (new PemObject ("EC PRIVATE KEY", o.getEncoded("DER"))); 
    // DER may already be the default but safer to (re)specify it 
    w.close(); 

+0

Danke für die Hilfe. Ich muss mit Option 3 (BC) versuchen, da ich gezwungen bin, dieses Problem in Java zu lösen. – dtseng

+0

Danke @ dave_thompson_085. Wie gehe ich zum Lesen und Laden dieser Art von Schlüssel zurück zu einer 'PrivateKey'-Instanz? – dtseng

+0

@ dtseng: mit BC, siehe meine Antwort auf https://stackoverflow.com/questions/22963581/reading-elliptic-curve-private-key-from-file-with-bouncycastle. Ohne BC und beschränkt auf Java müssten Sie das PKCS8 selbst (neu) konstruieren, was viel mehr ist, als in einen Kommentar passt. –

Verwandte Themen