EC公钥/私钥的Fileformat?

时间:2011-03-03 21:29:47

标签: file format bouncycastle elliptic-curve

如果我想将私钥和公钥都存储在一个文件中,那么最简单的格式是什么?特别是如果我打算将BouncyCastle库用于Java?

2 个答案:

答案 0 :(得分:3)

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

然而,棘手的是要说服加密提供者(例如BouncyCastle)提取公钥并和/或重新计算它。显然,如果您从PKCS#8编码的EC私钥中创建PKCS8EncodedKeySpec,该私钥也包含公钥,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()使用org.bouncycastle.jce.spec.ECPrivateKeySpec而不是无情地将私钥转换为JCEECPrivateKey类,但是在BouncyCastle中似乎尚未实现clean方法。

答案 1 :(得分: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)加密编码的私钥,否则文件会被盗,然后你无限期暴露。