privatekey java_Java 读取private Key

最近,用Fabric JAVA SDK做enroll动作的时候,在读取private Key的时候出现了一个错误:

org.bouncycastle.openssl.PEMException: problem parsing PRIVATE KEY: java.lang.IllegalArgumentException: wrong version for private key info

at org.bouncycastle.openssl.PEMParser$PrivateKeyParser.parseObject(Unknown Source)

at org.bouncycastle.openssl.PEMParser.readObject(Unknown Source)

at main.SampleUser.getPrivateKeyFromBytes(SampleUser.java:163)

at main.SampleUser$1.getKey(SampleUser.java:86)

at org.hyperledger.fabric.sdk.User.userContextCheck(User.java:94)

at org.hyperledger.fabric.sdk.HFClient.setUserContext(HFClient.java:257)

at main.carDemo.main(carDemo.java:68)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:282)

at java.lang.Thread.run(Thread.java:748)

Caused by: java.lang.IllegalArgumentException: wrong version for private key info

at org.bouncycastle.asn1.pkcs.PrivateKeyInfo.(Unknown Source)

at org.bouncycastle.asn1.pkcs.PrivateKeyInfo.getInstance(Unknown Source)

... 13 more

查看Openssl 版本

使用openssl verison或者openssl version -a查看。

OpenSSL 1.0.1e-fips 11 Feb 2013

built on: Mon Feb 20 14:38:48 UTC 2017

platform: linux-x86_64

options: bn(64,64) md2(int) rc4(16x,int) des(idx,cisc,16,int) idea(int) blowfish(idx)

compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DKRB5_MIT -m64 -DL_ENDIAN -DTERMIO -Wall -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -Wa,--noexecstack -DPURIFY -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM

OPENSSLDIR: "/etc/pki/tls"

engines: rdrand dynamic

定位问题

用线上生产环境的key测了下,没出现问题。初步判断,本地生成key的方式不同导致的。

在Stack Overflow上找了找。发现了一个回答,总结下:

核心原因

这个private key并不是PKC S8的格式。

详细说明

OpenSSL针对每种密码学算法支持四种PEM编码格式的private key。其中只有一种是PKCS8非加密的,也就是被Java PKCS8EncodedKeySpec所支持的(我用Node js压根就没有这个问题,还是推荐用node sdk啊)。也就是说我们可能使用了一种java并不支持的格式生成了private key文件。

这里,给出了一个链接(后续整理): How can I convert a .p12 to a .pem containing an unencrypted PKCS#1 private key block?针对RSA算法的转化进行了说明。

但是对于EC算法,有两个“传统的”编码格式是根据SEC1定义的(与RSA的PKCS1相同)。同时,PKCS8编码格式(对于所有的算法,并不仅限于RSA和EC)是被定义为PKCS8的。OpenSSL可以处理多种格式是因为PEM文件有两个特性:

BEGIN开头(非常重要)

END结尾(第二重要)

这两个信息定义了数据的类型。EC PRIVATE KEY代表了SEC1,PRIVATE KEY代表了PKCS8。

这里,我们有两种方法:

convert the OpenSSL key to PKCS8 unencrypted PEM with openssl pkcs8 -topk8 -nocrypt or just openssl pkey (in 1.0.0 up) -- or generate it as PKCS8 in the first place with genpkey or possibly req -newkey (both in 1.0.0 up) instead of ecparam -genkey. Use that blob de-base64-ed in PKCS8EncodedKeySpec。

if in addition to bcprov you have or get bcpkix, that handles many (maybe all?) OpenSSL formats that plain Java does not. Rebuild, or just revert to, the original PEM format (which can be in memory) and you can parse with PEMReader and then convert with JcaPEMKeyConverter (or just a KeyFactory).

这里有一个RSA文件转化的实例。EC算法可以参考这个改一下。

自己实现PEMParser

当然,我们可以自己实现PEMParser的功能,前提是我们已经获得了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());

}

最后,其实我们并不需要java来做这件事情,OpenSSL完全提供了ECDH(其他算法也ok?)的agreement/derivation。所以,可以直接使用OpenSSL脚本来执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值