概述:
在Java编程中,我们经常用到如下一段代码来生成RSA公私钥,分别拿到公私钥然后加解密计算:
KeyPairGenerator keyPairGen;
keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
本文讲述仅有RSAPrivateKey privateKey,没有KeyPair keyPair,如何通过RSAPrivateKey privateKey得到RSAPublicKey publicKey
分析RSAPrivateKey:
RSAPrivateKey privateKey,通过函数privateKey.getAlgorithm()查看,或者通过privateKey.getEncoded()数据分析,可以得到默认是PKCS#8格式,
privateKey.getEncoded()的数据例子:
通过TLV分析工具查看:
可以看到,RSAPrivateKey privateKey里面,RSA密钥的参数N、E、D、P、Q等都包含在内的。
其中N、E是私钥对应的公钥RSAPublicKey publicKey,所需的全部参数。
因此,是可以从RSAPrivateKey privateKey拿到对应的RSAPublicKey publicKey
开发环境:
`IDE:eclipse版本4.20.0
编译器:JDK1.8
导入的包:bouncycastle,jar文件名bcprov-jdk18on-171.jar
转换函数:
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();
}
public static RSAPublicKey rsaGetPubKeyFromPriKey(RSAPrivateKey privateKey) {
RSAPublicKeySpec rsaPubKeySpec = null;
KeyFactory keyFactory = null;
org.bouncycastle.asn1.pkcs.RSAPrivateKey rP = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
rP = org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(p8PrvKey2P1PrvKeyBytes(privateKey));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
keyFactory = KeyFactory.getInstance("RSA");
rsaPubKeySpec = new RSAPublicKeySpec(rP.getModulus(), rP.getPublicExponent());
return (RSAPublicKey) keyFactory.generatePublic(rsaPubKeySpec);
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
注意导入bcprov-jdk18on-171.jar中类
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
还要注意,bouncycastle里面有RSAPrivateKey
jdk自带公共:java.security.interfaces.RSAPrivateKey;
和
bouncycastle包里面的:org.bouncycastle.asn1.pkcs.RSAPrivateKey
测试代码:
public static void main(String[] args) {
testRsa();
}
public static void testRsa() {
KeyPairGenerator keyPairGen;
try {
keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(2048, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//System.out.println("privateKey:" + hexToString(privateKey.getEncoded(), 0, privateKey.getEncoded().length));
//RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPublicKey publicKey = rsaGetPubKeyFromPriKey(privateKey);
String out1 = encrypt("1234567890", publicKey);
System.out.println("encrypt:" + out1);
String out2 = decrypt(out1, privateKey);
System.out.println("decrypt:" + out2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String encrypt(String str, RSAPublicKey publicKey) throws Exception {
//base64编码的公钥
//byte[] decoded = Base64.getDecoder().decode(publicKey);
//RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
public static String decrypt(String str, RSAPrivateKey privateKey) throws Exception {
//64位解码加密后的字符串
byte[] inputByte = Base64.getDecoder().decode(str);
//base64编码的私钥
//byte[] decoded = Base64.getDecoder().decode(privateKey);
//RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}