0、前言
本文仅局限于RSA密钥的相关内容,其他算法的密钥请自行参考研究
本文基于java1.8 和 BC version 1.7(引入依赖包)
如果你不知道BC库是什么,那么建议先行搜索了解一下
1、PKCS8标准的私钥转PCKS1标准的私钥字节数组
/**
* PKCS8标准的私钥转PCKS1标准的私钥字节数组(或者可以说是从中提取出最原始的密钥算法的那一部分内容)
* @param privateKey java默认的PKCS8标准的私钥对象
* @return PCKS1标准的私钥字节数组
* @throws Exception 异常
*/
public static byte[] p8PrvKey2P1PrvKeyBytes(PrivateKey privateKey) throws Exception {
PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded());
ASN1Encodable privateKeyPKCS1ASN1Encodable = privateKeyInfo.parsePrivateKey();
ASN1Primitive asn1Primitive = privateKeyPKCS1ASN1Encodable.toASN1Primitive();
return asn1Primitive.getEncoded();
}
2、将java.security.PrivateKey转换成org.bouncycastle.asn1.pkcs.RSAPrivateKey对象
/**
* 将java.security.PrivateKey转换成org.bouncycastle.asn1.pkcs.RSAPrivateKey对象
* @param privateKey java.security.PrivateKey对象
* @return org.bouncycastle.asn1.pkcs.RSAPrivateKey对象
*/
public static RSAPrivateKey prvKey2BCRSAPrvKey(PrivateKey privateKey) throws Exception {
// 这里getInstance只接受PKCS1的私钥转换成的byte数组,否则会报错
// 报错信息:org.bouncycastle.asn1.DLSequence cannot be cast to org.bouncycastle.asn1.ASN1Integer
// 所以需要先转换成PKCS1的私钥信息,才能输入进来
// 这里输入asn1Primitive也可以
RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(p8PrvKey2P1PrvKeyBytes(privateKey));
System.out.println("RSA key version is: " + rsaPrivateKey.getVersion());
return rsaPrivateKey;
}
3、利用算法原理判定密钥对是否匹配
/**
* 验证一个公钥和一个私钥是否匹配,一般就是加密一个数据,然后解密,看看解密后的结果与原始数据是否一致。 <br/>
* 否则就像这样利用算法原理,去验证RSA公私钥是否匹配
* @param publicKey 公钥
* @param privateKey 私钥
* @return true-匹配,false-不匹配
* @throws Exception 异常
*/
public static boolean validRSAKeyPairMatch(PublicKey publicKey, PrivateKey privateKey) throws Exception {
// 必须把私钥转成BC库里的RSA私钥对象,才是PKCS1标准的私钥形式,此时才能依据私钥获取一些理论算法中提及的各种密钥参数
RSAPrivateKey rsaPrivateKey = prvKey2BCRSAPrvKey(privateKey);
// 从私钥中获取公钥的指数
BigInteger prvE = rsaPrivateKey.getPublicExponent();
// 从私钥中获取密钥对共用的模数
BigInteger prvM = rsaPrivateKey.getModulus();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 把公钥加载成RSA公钥spec对象,以此获取公钥的指数
RSAPublicKeySpec pubKeySpec = keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);
// 依据公钥获取公钥的指数
BigInteger pubE = pubKeySpec.getPublicExponent();
// 依据公钥获取密钥对共用的模数
BigInteger pubM = pubKeySpec.getModulus();
// 如果 利用私钥推算出的公钥的参数 和 公钥自身的参数 二者是一致的,说明这个公钥和这个私钥是匹配的,是一对的
return prvE != null && prvM != null && prvE.equals(pubE) && prvM.equals(pubM);
}
4、验证一个私钥与一本证书是否匹配
其实就是先从证书中提取公钥(利用证书对象就可以直接get到公钥对象),然后就是和上一环节一样的流程(目前没有找到更便捷的流程)
5、测试
N、补充
本文使用代码基于我写的存放于github的公开代码(点击前往仓库),欢迎前去查看是否有遗漏或者bug或者复制下来检验
如果你觉得本文对你有所收获,请点赞、转发,让更多人看到这篇文章,谢谢!!!
如果你觉得有哪里不对,也欢迎在评论区留言指教!!!