2017-12-12 51 views
0

Java Private.pemを正しく構築する方法については助けが必要です。私はECDSAのpemファイルをJavaで作成し、一つはpythonで作成しました。私はpythonの1つを正しく実装していますが、Javaのものは正しくありません。 ASN1についてJavaでのECDSAのPEMエンコーディング

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); 
} 

JavaとPythonの両方のOpenSSLの(その長さのためhexdumpに対しては含まない)を用いて解析:

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----- 

:出力PEMとして

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  

をヘルプは非常に高く評価されるだろう!

+0

JCEを ' PrivateKey.getEncoded() 'は、暗号化されていないPKCS8エンコーディングを返します。正しいPEMタイプは 'BEGIN/END PRIVATE KEY'(' EC'のような特定のアルゴリズムなし)であり、次にOpenSSLとOpenSSLと互換性のあるものがそれを読み込みます。 OpenSSLの「伝統的な」アルゴリズム固有の形式が必要な場合は、より難しいが大部分は二重である。私は今は行かなければならないが、必要に応じて後でそれを埋めることができる。 PS:ECキー/キーパーはECDSAでは使用可能ですが、これに限定されません。 _Cert_ OTOHは、KeyUsageによって制限されます。 –

+0

情報ありがとうございます。 java pemの出力はこの仕様に適合しなければなりません:https://tools.ietf.org/html/rfc5915。それは、ECプライベートキーを持つことになっています。両方のキーには、secp256k1カーブが含まれています。 16進数のダンプはJavaの方が長くなり、整数は1ではなく0になります。正しいものにするために細部にどのように入るのかについてはあまり確かではありません。私は現在MiscPEMGeneratorを使って正しい出力に到達するのに役立つかどうか試しています。 – dtseng

+0

あなたは本当にコブライツ曲線を意図しましたか?通常は、NIST P-256 – lockcmpxchg8b

答えて

2

(遅れて申し訳ありません。)

さて、あなたは、アルゴリズム固有のフォームが必要ですが、JCEはPrivateKey.getEncoded() PKCS8が希望を除いて、ほとんどECC How can I convert a .p12 to a .pem containing an unencrypted PKCS#1 private key block?と同じQであるエンコーディング、(すべてのアルゴリズムを処理します)を返しますRSAではなく、(もっと重要な)Java とBouncyCastleを使用しています。

だから、あなたのオプションは次のとおりです。

  • はPEMに直接バイナリ(DER)のいずれかで、PKCS8エンコーディングを書き、アルゴリズム固有に変換するopenssl ecまたは1.1.0 openssl pkey -traditionalでの使用PEMフォームはSEC1です(rfc5915は基本的にSEC1の再発行です)。

  • PKCS8エンコーディング(PEMまたはDERのいずれか)を記述し、openssl asn1parse -strparseを使用してアルゴリズム固有の部分を抽出するか、アルゴリズム固有の部分のオフセットを決定して直接抽出します。 256ビットのECCキーペアDERは、ほとんどの場合、1オクテットの長さでエンコードしますが、(名前付き)カーブを識別するOIDは、異なるカーブのサイズが異なる場合があります。あなたの例が示すように、secp256k1では24 + 2なので、現在のロジックにはArrays.copyOfRange(Key,26,Key.length)を与えることができます。

    ECC鍵ペアが256ビットより大きい場合、DERエンコーディングは変更する必要があり、境界線の近くでは、キーペアの公開値が非圧縮形式であるか圧縮形式であるかによって異なります(JCEはエンコーディング内のオプションを提供しません)。この場合、DERの少なくとも一部を手動で処理する必要があります。その場合は、代わりに次のオプションに移動します。すでに使用している

  • BCは、PKCS8構造を操作する機能を公開し、あなたは、このようなアルゴリズム固有のSEC1エンコーディングを抽出するためにそれを使用することができます

 
    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

ありがとうございます。私はオプション3(BC)を試してみる必要があります。なぜなら、私はこの問題をJavaで解決することに拘束されているからです。 – dtseng

+0

ありがとう@ dave_thompson_085。このタイプのキーを読み込み、読み込んで 'PrivateKey'インスタンスに戻すにはどうすればいいですか? – dtseng

+0

@dtseng:BCと、https://stackoverflow.com/questions/22963581/reading-elliptic-curve-private-key-from-file-with-bouncycastleへの私の答えを見てください。 BCに縛られずにJavaに制約されていれば、自分自身でPKCS8を構築する必要があります。 –

関連する問題