Java 从未压缩的客户端临时公钥和开放SSL静态服务器私钥生成ECPublicKey/ECPrivateKey时出错
希望在这里得到一些帮助 我试图从未压缩的客户端公钥(0x04 | 32字节点X | 32字节点Y)和服务器私钥(openSSL生成的base64)生成共享密钥,但在将服务器EC私钥转换为EC密钥对象时出错。我需要这些来生成共享秘密 我正在使用- 1.曲线为P256R1 2.服务器私钥是使用openSSL生成的(目前在代码中是硬编码的) 3.客户端公共以未压缩格式共享(格式0x04 | 32字节点X | 32字节点Y) 错误Java 从未压缩的客户端临时公钥和开放SSL静态服务器私钥生成ECPublicKey/ECPrivateKey时出错,java,cryptography,bouncycastle,shared-secret,Java,Cryptography,Bouncycastle,Shared Secret,希望在这里得到一些帮助 我试图从未压缩的客户端公钥(0x04 | 32字节点X | 32字节点Y)和服务器私钥(openSSL生成的base64)生成共享密钥,但在将服务器EC私钥转换为EC密钥对象时出错。我需要这些来生成共享秘密 我正在使用- 1.曲线为P256R1 2.服务器私钥是使用openSSL生成的(目前在代码中是硬编码的) 3.客户端公共以未压缩格式共享(格式0x04 | 32字节点X | 32字节点Y) 错误 2018-02-26 14:31:12.818[0;39m [31mER
2018-02-26 14:31:12.818[0;39m [31mERROR[0;39m [35m18096[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.a.c.c.C.[.[.[/].[dispatcherServlet] [0;39m [2m:[0;39m Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.security.spec.InvalidKeySpecException: java.lang.IllegalArgumentException: wrong version for private key info] with root cause
java.security.spec.InvalidKeySpecException: java.lang.IllegalArgumentException: wrong version for private key info
at org.bouncycastle.jce.provider.JDKKeyFactory$EC.engineGeneratePrivate(Unknown Source) ~[bcprov-jdk15-140.jar:1.40.0]
at java.security.KeyFactory.generatePrivate(KeyFactory.java:366) ~[na:1.8.0_77]
TLDR:该私钥不是PKCS8 OpenSSL支持每种算法四种不同的PEM私钥格式(总共大约十二种);其中只有一种是PKCS8 unencrypted,这是Java PKCS8EncodedKeySpec所要求的格式,您使用的是另一种Java不支持的格式。与RSA的比较;对于EC,这两种“传统”格式由SEC1 from定义(对于RSA,则由PKCS1定义),而PKCS8格式(对于所有算法,而不仅仅是EC和RSA),则由PKCS8定义。OpenSSL能够处理多种格式,主要是因为PEM文件有一个非常重要的开始行(不太重要的结束行)来指定数据类型;删除文件之前,文件的类型为
EC PRIVATE KEY
表示SEC1而不是typePRIVATE KEY
表示Java使用的PKCS8未加密
您有两个(或更多)选项:
- 使用
或只是OpenSSL-PKCS8-topk8-nocrypt
(在1.0.0以上版本中)将OpenSSL密钥转换为PKCS8未加密的PEM,或者首先使用OpenSSL-pkey
或可能的genpkey
(在1.0.0以上版本中)而不是req-newkey
将其生成为PKCS8。在PKCS8EncodedKeySpec中使用该blob de-base64-edecparam-genkey
- 如果除了bcprov之外,您还拥有或获得了bcpkix,那么它可以处理许多(可能全部?)OpenSSL格式,而普通Java无法处理这些格式。重新生成或恢复为原始PEM格式(可存储在内存中),您可以使用
进行解析,然后使用PEMReader
(或仅使用JcaPEMKeyConverter
)进行转换KeyFactory
- 或者,由于您已经完成了PEM解析的一部分,因此您可以按照
所做的相同方式自己处理其余部分,仅对私有部分进行简化:PEMParser
- 最后,您并不需要Java来实现这一点。OpenSSL可以在库中(从您编写的代码调用)或命令行中执行ECDH密钥协商/派生,但对于后者,您需要PEM文件中的密钥:OpenSSL支持的任何PEM格式的私钥(您已经拥有),但X.509 SubjectPublicKeyInfo格式的对等公钥,根据您提供的信息,您可能不需要也可能需要构建
TLDR:该私钥不是PKCS8 OpenSSL支持每种算法四种不同的PEM私钥格式(总共大约十二种);其中只有一种是PKCS8 unencrypted,这是Java PKCS8EncodedKeySpec所要求的格式,您使用的是另一种Java不支持的格式。与RSA的比较;对于EC,这两种“传统”格式由SEC1 from定义(对于RSA,则由PKCS1定义),而PKCS8格式(对于所有算法,而不仅仅是EC和RSA),则由PKCS8定义。OpenSSL能够处理多种格式,主要是因为PEM文件有一个非常重要的开始行(不太重要的结束行)来指定数据类型;删除文件之前,文件的类型为
EC PRIVATE KEY
表示SEC1而不是typePRIVATE KEY
表示Java使用的PKCS8未加密
您有两个(或更多)选项:
- 使用
或只是OpenSSL-PKCS8-topk8-nocrypt
(在1.0.0以上版本中)将OpenSSL密钥转换为PKCS8未加密的PEM,或者首先使用OpenSSL-pkey
或可能的genpkey
(在1.0.0以上版本中)而不是req-newkey
将其生成为PKCS8。在PKCS8EncodedKeySpec中使用该blob de-base64-edecparam-genkey
- 如果除了bcprov之外,您还拥有或获得了bcpkix,那么它可以处理许多(可能全部?)OpenSSL格式,而普通Java无法处理这些格式。重新生成或恢复为原始PEM格式(可存储在内存中),您可以使用
进行解析,然后使用PEMReader
(或仅使用JcaPEMKeyConverter
)进行转换KeyFactory
- 或者,因为您已经完成了PEM解析的一部分,所以您可以自己处理其余部分
import java.security.*; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; ... static void SO48996981BCparseECprivate () throws Exception { byte[] server_sec1 = DatatypeConverter.parseBase64Binary("MHgCAQEEIA27nM1klj9pVxOzJrO4aBLFvXTtOJnf+vMhiv3HA+3noAsGCSskAwMCCAEBB6FEA0IABG1erLtLyTbC5yN8gVY4a0JPO5eefKftWMbSQij2Ks5TaNNuj/tqigFqsk1g/l2UBBkIx2KdpeiY8nVddwMpzho="); ASN1Sequence seq = ASN1Sequence.getInstance(server_sec1); org.bouncycastle.asn1.sec.ECPrivateKey pKey = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(seq); AlgorithmIdentifier algId = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, pKey.getParameters()); byte[] server_pkcs8 = new PrivateKeyInfo(algId, pKey).getEncoded(); KeyFactory fact = KeyFactory.getInstance ("EC","BC"); PrivateKey pkey = fact.generatePrivate (new PKCS8EncodedKeySpec(server_pkcs8)); // for test only: System.out.println (pkey.getClass().getName() + " " + pkey.getAlgorithm()); }2018-02-26 14:31:12.818[0;39m [31mERROR[0;39m [35m18096[0;39m [2m---[0;39m [2m[nio-8080-exec-1][0;39m [36mo.a.c.c.C.[.[.[/].[dispatcherServlet] [0;39m [2m:[0;39m Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.security.spec.InvalidKeySpecException: java.lang.IllegalArgumentException: wrong version for private key info] with root cause java.security.spec.InvalidKeySpecException: java.lang.IllegalArgumentException: wrong version for private key info at org.bouncycastle.jce.provider.JDKKeyFactory$EC.engineGeneratePrivate(Unknown Source) ~[bcprov-jdk15-140.jar:1.40.0] at java.security.KeyFactory.generatePrivate(KeyFactory.java:366) ~[na:1.8.0_77]