秘密鍵と公開鍵の両方を 1 つのファイルに保存したい場合、最も使いやすい形式は何ですか? 特に、Java 用の BouncyCastle ライブラリを使用する予定がある場合はどうなりますか?
2 に答える
理論的な観点では、公開鍵は秘密鍵から再計算できます (そのための計算コストは、単一の ECDSA 署名を生成するためのコスト、または ECDH の半分を実行するためのコストよりもわずかに低いため、高速です)。したがって、概念的には、秘密鍵のみを保存する必要があり、その標準形式はPKCS#8であり、これは Java with でサポートされていますjava.security.spec.PKCS8EncodedKeySpec
。さらに、PKCS#8 形式には、同じ blob 内の秘密鍵に沿って公開鍵をオプションでエンコードするための規定が含まれているため、これは実際に探しているものと同じように見えます。
ただし、難しいのは、暗号化プロバイダー (BouncyCastle など) に公開鍵をそのまま抽出したり、再計算させたりすることです。どうやら、PKCS8EncodedKeySpec
公開鍵も含む PKCS#8 でエンコードされた EC 秘密鍵から を作成すると、BouncyCastle は親切にも、エンコードされた公開鍵のコピーを内部に保持し、秘密鍵を再エンコードする場合はそれを書き戻します。 PKCS#8 形式で。ただし、それ以外には何もしません。不透明なブロブとして処理します。
したがって、公開鍵を再計算する必要があります。JCE と BouncyCastle API と未実装のビットを調べたところ、次のように見えました (JDK 1.6.0_24、BouncyCastle 1.46)。
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Provider;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.provider.JCEECPrivateKey;
import org.bouncycastle.jce.provider.JCEECPublicKey;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
// Create the provider and an appropriate key factory.
Provider pp = new BouncyCastleProvider();
KeyFactory kf = KeyFactory.getInstance("EC", pp);
// Decode the private key (read as a byte[] called 'buf').
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(buf);
PrivateKey sk = kf.generatePrivate(ks);
// Recompute public key.
JCEECPrivateKey priv = (JCEECPrivateKey)sk;
ECParameterSpec params = priv.getParameters();
ECPublicKeySpec pubKS = new ECPublicKeySpec(
params.getG().multiply(priv.getD()), params);
PublicKey pk = kf.generatePublic(pubKS);
// To reencode the private key.
buf = kf.getKeySpec(sk, PKCS8EncodedKeySpec.class).getEncoded();
概念的には、無慈悲に秘密鍵をクラスにキャストするのではなくkf.getkeySpec()
withを使用する必要がありますが、BouncyCastle ではクリーン メソッドはまだ実装されていないようです。org.bouncycastle.jce.spec.ECPrivateKeySpec
JCEECPrivateKey
これを試してください (BouncyCastle v1.47、JDK 1.7.* を使用していますが、JDK 1.6.* でも問題ないと思います):
// Recreate the private key.
final KeyFactory kf = KeyFactory.getInstance("EC", "BC");
final PKCS8EncodedKeySpec encPrivKeySpec = new PKCS8EncodedKeySpec(rawPrivKey);
final PrivateKey privKey = kf.generatePrivate(encPrivKeySpec);
final byte[] rawPrivKey = privKey.getEncoded();
// Recreate the public key.
final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(rawPubKey);
final PublicKey pubKey = kf.generatePublic(pubKeySpec);
final byte[] rawPubKey = pubKey.getEncoded();
ここでrawPrivKey
、 とrawPubKey
はバイト型の配列です。
暗号化された秘密鍵をブロック暗号 (つまり AES) で暗号化することをお勧めします。暗号化しないと、ファイルが盗まれる可能性があり、無期限に公開されます。