4

如果我想将私钥和公钥存储在一个文件中,最容易使用的格式是什么?特别是如果我打算为 Java 使用 BouncyCastle 库?

4

2 回答 2

3

从理论上讲,公钥可以从私钥重新计算(计算成本略低于产生单个 ECDSA 签名的成本,或者做 ECDH 的一半,所以速度很快)。因此,从概念上讲,您只需存储私钥,其标准格式是PKCS#8,Java 支持java.security.spec.PKCS8EncodedKeySpec. 此外,PKCS#8 格式包括在同一个 blob 中可选地沿着私钥对公钥进行编码的规定,因此这看起来确实像您要查找的内容。

然而,棘手的事情是说服密码提供者(例如 BouncyCastle)提取公钥和/或重新计算它。显然,如果您PKCS8EncodedKeySpec从还包含公钥的 PKCS#8 编码的 EC 私钥创建一个,BouncyCastle 将在内部保留编码公钥的副本并在您决定重新编码私钥时将其写回PKCS#8 格式。但是,它对它没有任何作用。它将其作为不透明的 blob 处理。

因此,您必须重新计算公钥。通过 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()withorg.bouncycastle.jce.spec.ECPrivateKeySpec而不是无情地将私钥强制转换为JCEECPrivateKey类,但是在 BouncyCastle 中似乎还没有实现 clean 方法。

于 2011-03-04T15:29:47.800 回答
0

试试这个(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();

其中rawPrivKeyrawPubKey是字节类型的数组。
我建议您使用分组密码(即 AES)对编码的私钥进行加密,否则文件可能会被盗,然后您将被无限期暴露。

于 2012-06-19T13:15:45.437 回答