首页 > 解决方案 > 如何从私钥字节创建 PrivateKey 对象?

问题描述

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

据我所见,它是这样的:

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

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

所以我的问题是:如何将我的私钥字节编码为 PKCS #8,或者,除了 PKCS8EncodedKeySpec 之外,是否还有其他类可以执行此操作?

我正在使用 ECDSA

我正在使用 secp256k1

标签: javacryptographyjce

解决方案


...我是否将我的私钥字节编码为 PKCS #8,或者,除了 PKCS8EncodedKeySpec 之外,还有其他类可以执行此操作吗?

是的,是的。

选项 A:构建像 PKCS8 这样的 DER 编码通常可能很复杂,但是对于包含“命名”(OID)形式的 EC 密钥的 PKCS8 未加密的特定情况,这是现在每个人(尤其是 Java 加密)都使用的, 更简单,并且对于给定的曲线由固定前缀和后跟私钥字节组成。请参阅我对这个 Q的回答,主要是关于私钥计算公钥,但我的示例在回答其他问题的过程中使用了 PKCS8 化的私钥。

JavaSE 中的注意事项(在该答案之后发布)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 参数;如果你愿意,我可以找到一些骗子。

警告:如果“躺在某处”不是使用足够熵正确实现的随机过程的输出,特别是“种子”是由人类选择或记住的,那么这样做是不安全的。如果你将它用于比特币——你没有说,但这是大多数无知、未受过训练的人的用例,他们突然想要做 ECC,因为他们认为这会让他们变得更酷、l33t、富有、性感和著名的——你可能会赔钱;请参阅https://en.bitcoin.it/wiki/Brainwallet。但这对于 StackOverflow 来说是题外话。


推荐阅读