因为openssl 1.0以前的版本对私钥编码方式和PKCS#8私钥编码方式有点不同.如果你查看PKCS#8,你可以看到私钥的ASN.1 module如下:
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
privateKey PrivateKey,
attributes [0] Attributes OPTIONAL }
Version ::= INTEGER {v1(0)} (v1,...)
PrivateKey ::= OCTET STRING ----openssl的传统编码
Attributes ::= SET OF Attribute
如果在Java程序中使用PrivateKey.getEncoded()方法的话,得到的是整个PKCS8的结构的ASN.1的DER编码.而openssl1.0以前的私钥编码方式中是直接对上面的那个OCTET STRING进行编码的,也就是说,里面只包含了RSA私钥的几个必须的BigInteger.如果需要用JCE生存私钥文件,再由Openssl1.0以前的来使用该私钥文件,则需要进行转换。基于BouncyCastle我们可以很方便的写出这样子的转换方法。
public byte[] getOpensslEncodeKey(PrivateKey pKey){
try
{
RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) pKey;
RSAPrivateKeyStructure rsastruct = new RSAPrivateKeyStructure(
rsaKey.getModulus(), rsaKey.getPublicExponent(),
rsaKey.getPrivateExponent(), rsaKey.getPrimeP(),
rsaKey.getPrimeQ(), rsaKey.getPrimeExponentP(),
rsaKey.getPrimeExponentQ(), rsaKey.getCrtCoefficient());
ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
DEROutputStream deroutputstream = new DEROutputStream(
bytearrayoutputstream);
deroutputstream.writeObject(rsastruct.getDERObject());
deroutputstream.close();
return bytearrayoutputstream.toByteArray();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
这样,就可以了。
从openssl1.0以后的版本,对私钥编码就是按PKCS#8私钥编码来处理的了,这就和在Java程序中使用PrivateKey.getEncoded()方法是相同的,两者可以通用的。.
最后需要说明的是, 如果要将私钥文件保存为PEM编码那么私钥的文件头也是一个很重要的问题。通过以上转换的getOpensslEncodeKey这个接口转换的私钥需要在头中指明私钥的算法类型,比如RSA的私要要用“-----BEGIN RSA PRIVATE KEY-----”和"-----END RSA PRIVATE KEY-----",否则openssl被报无法加载私钥文件的错误。对于采用PrivateKey.getEncoded()得到的私钥,又必须采用"-----BEGIN PRIVATE KEY-----"和"-----END PRIVATE KEY-----",否则openssl也将被报无法加载私钥文件的错误。