如何从私钥字节创建 PrivateKey 对象?

How do I create a PrivateKey object from private key bytes?

假设我有一个种子:this is a seed that i might have lying around somewhere
然后我对种子进行哈希处理以生成一个大小为 32
的字节数组 据我了解(来自 this 文章),现在这是我的私钥字节。我如何将这些字节转换为 PrivateKey 对象?

据我所见,它类似于:

KeyFactory kf = KeyFactory.getInstance("EC");
PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

但要使其正常工作,私钥字节应采用 PKCS #8 格式。由于我通过散列种子生成了我的私钥字节,所以它们显然不是。

所以我的问题是:如何将我的私钥字节编码到 PKCS #8 中,或者,除了 PKCS8EncodedKeySpec 之外,还有另一个 class 可以做到这一点吗?

我正在使用 ECDSA

我正在使用 secp256k1

... do I encode my private key bytes into PKCS #8, OR alternatively, is there another class to do this besides PKCS8EncodedKeySpec?

是的,是的。

选项 A:构建像 PKCS8 这样的 DER 编码一般来说可能很复杂,但对于包含 'named' (OID) 形式的 EC 密钥的未加密 PKCS8 的特定情况,这是每个人(和特别是现在使用的 Java crypto) 更简单,并且对于给定的曲线,它由一个固定的前缀和紧随其后的私钥字节组成。请参阅我对 的回答,其中主要是关于从 私钥计算公钥 ,但我的示例在回答其他内容的过程中使用了 PKCS8 化的私钥。

注意 java 9 up(在该答案后发布)java.xml.bind.DatatypeConverter 在 JavaSE 中默认不再可用,因此您需要将其作为依赖项或替代项功能上等同的东西——关于这个有很多问题。

选项 B:您可以使用 ECPrivateKeySpec 而不是使用 PKSC8(编码)表示。正如该答案中还指出的那样,标准 (Oracle/Open) Java 不提供单独获取参数的简单方法,因此我发现的最好方法是生成一个虚拟密钥并将其丢弃:

KeyPairGenerator kg = KeyPairGenerator.getInstance("EC");
kg.init(new ECGenParameterSpec("secp256k1"));
ECParameterSpec param = ((ECPublicKey)kg.generateKeyPair().getPublic()).getParams();
BigInteger s = new BigInteger(1, /*byte[32] privatekey value*/);
KeyFactory kf = KeyFactory.getInstance("EC");
PrivateKey kp = kf.generatePrivate(new ECPrivateKeySpec(s, param));
// castable to ECPrivateKey if desired/needed

如果您改为使用 BouncyCastle 的直接(非 JCA)API,它会按名称提供 EC 参数;如果你愿意,我可以找到一些骗子。

警告:如果 'lying around somewhere' 不是使用足够熵正确实现的随机过程的输出,特别是 'seed' 是由人类选择或记住的,那么这样做是 不安全。如果你将它用于 Bitcoin——你没有说,但这是大多数无知、未经训练的人的用例,他们突然想做 ECC,因为他们认为这会让他们sooper-kewl,l33t,富有,性感和名气——你可能会赔钱;见 https://en.bitcoin.it/wiki/Brainwallet 。但那是 Whosebug 的题外话。