RSA是一种非对称加密,发送方用公钥加密,接收方用私钥解密。只要私钥不泄漏,即使获得了公钥和数据,也无法进行解密。RSA的安全性依赖于大整数因式分解的困难,目前已知被分解的最大整数为768个二进制位,也就是说已知能被破解的最大RSA秘钥为768位,但是一般情况都采用1024位的秘钥,重要数据使用2048位的秘钥(当然安全性的提升要付出更多的解密时间)。
首先生成公钥和私钥:
public static void main(String[] args) {
try {
KeyPairGenerator kp = KeyPairGenerator.getInstance("RSA");
kp.initialize(1024); // 要是需要2048的秘钥的话就修改一下参数
KeyPair keyPair = kp.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
System.out.println("公钥为:" + new String(Base64.getEncoder().encode(publicKey.getEncoded())));
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("私钥为:" + new String(Base64.getEncoder().encode(privateKey.getEncoded())));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
执行就能得到结果:
公钥为:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl0vjjliUX5ZfefPqQ8Mf57EBRWqcHHggs6AYRHYVWJWxkpSTYFbCLuU7R6MnAIaWFZrfLvVfTNE6or7aDmbeHFnYHOZwvZfPRPDL3Iu915wTM3Ns62kQuXNbHNspN/xxiLnSjzMUvbnL5aVc/NJazzuMg+FVma910w9i2c2EMmwIDAQAB
私钥为:MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOXS+OOWJRfll958+pDwx/nsQFFapwceCCzoBhEdhVYlbGSlJNgVsIu5TtHoycAhpYVmt8u9V9M0TqivtoOZt4cWdgc5nC9l89E8Mvci73XnBMzc2zraRC5c1sc2yk3/HGIudKPMxS9ucvlpVz80lrPO4yD4VWZr3XTD2LZzYQybAgMBAAECgYBHnZRdJv5sEelfNUbHP6CxKoNoVn1R5HPbunmZf7969rJuMl/mzetzvszm8EleC54OkdGYNWpWsCgKvKZ9H7tmT8yQfIwP5uvXZY9bbnL0mSU97LmdvJ/NW0+BDZYTz0Uz0OV6yvyluBe4g7YqhckzXToLO8SJrIB15W6hx2qhgQJBAPiBqvkZOPYL3ey9h+hhMyOE9VfFm/LxHxoCFM6MaN4IkBWCoOFMHoK7U4gVOwio3cURBUlHN5wlITwcyvktYbsCQQDswRYqJDBJ5tF412yy8RpF0glJRVM2FAgG0zz8bBvEYJMRVSVi9+Q1u+cFgIPvHDpkaOEezLq+pR3uBGKJ92KhAkBm3n5g+UDsEUN/sYFl/36E0JAjEkkZCxk90ei9C8CJUPAcB2QDf1gN8++DII68afLLld0jVVi+yVv1n1GiTlfrAkEAhrCCj47u+dwap4jHCjYoIDiRl+GcqVNUDa33MBPA6EOY529tSZSFfBxeHb8zT8DbZ2xTRlZqlzMQh+xustbOgQJBAJSq6ioVUR8YwYMl0VD4svuZiuv6aAu2P1BK3f/ftbPyDPm3SKn3TV0/Rpe3KJO1Di2G+8gXyR8tge6Dm3RAdoU=
当然每次得到的公钥私钥都是不一样的,然后把公钥交给发送方以进行加密:
public static void main(String[] args) {
// 公钥字符串,这里直接赋值了,当然一般不会这么写,把公钥放在一个数据文件或者配置里面去获取
String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDl0vjjliUX5ZfefPqQ8Mf57EBRWqcHHggs6AYRHYVWJWxkpSTYFbCLuU7R6MnAIaWFZrfLvVfTNE6or7aDmbeHFnYHOZwvZfPRPDL3Iu915wTM3Ns62kQuXNbHNspN/xxiLnSjzMUvbnL5aVc/NJazzuMg+FVma910w9i2c2EMmwIDAQAB";
try {
// 把公钥字符串转换成对象
byte[] publicKeyBy = Base64.getDecoder().decode(publicKeyStr.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBy));
// 以上获得的PublicKey可以固化下来,只要秘钥不变,就可以一直使用,但是下面的cipherPublic 不要固化!因为他不是线程安全的,如果使用同一个cipherPublic 并发访问时可能会抛出异常javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
Cipher cipherPublic = Cipher.getInstance("RSA");
// 设置为加密模式并设置公钥
cipherPublic.init(Cipher.ENCRYPT_MODE, publicKey);
// 定义一个发送的数据
String sendMsg = "你好呀!";
// 获得加密的byte[]
byte[] encryptByte = cipherPublic.doFinal(sendMsg.toString().getBytes("UTF-8"));
// 转变成字符串以进行传输
String strKey = Base64.getEncoder().encodeToString(encryptByte);
System.out.println("加密后的数据为:" + strKey);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
得到的结果为:
加密后的数据为:dBz/nSJ+jK13dhEhNZOeBcMgQjJfauWP9xl0OLYKiuhKOzYbI+zOezyM1PhHqTvl3hjaTf+wzpzUd+2p75v4Zn8sxSmRw8CIzXTtY/4g3v94cdZbvTfWe+snLXt7qTMdK9grrBqSvBhp/JsOPhd336h/lo77mYd0XEUNJhIFyl0=
获得加密数据后接收方就可以进行相应的解密了,不过要注意一些传输方式会破坏加密数据,如url的get方式传输时,加密数据的’+'会被转换成 ’ ',所以接收到数据之后要注意转换回来,不然就解密错误了:
public static void main(String[] args) {
// 私钥字符串,这里直接赋值了,同样的,可以把私钥放在一个数据文件或者配置里面去获取
String privateKeyStr = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOXS+OOWJRfll958+pDwx/nsQFFapwceCCzoBhEdhVYlbGSlJNgVsIu5TtHoycAhpYVmt8u9V9M0TqivtoOZt4cWdgc5nC9l89E8Mvci73XnBMzc2zraRC5c1sc2yk3/HGIudKPMxS9ucvlpVz80lrPO4yD4VWZr3XTD2LZzYQybAgMBAAECgYBHnZRdJv5sEelfNUbHP6CxKoNoVn1R5HPbunmZf7969rJuMl/mzetzvszm8EleC54OkdGYNWpWsCgKvKZ9H7tmT8yQfIwP5uvXZY9bbnL0mSU97LmdvJ/NW0+BDZYTz0Uz0OV6yvyluBe4g7YqhckzXToLO8SJrIB15W6hx2qhgQJBAPiBqvkZOPYL3ey9h+hhMyOE9VfFm/LxHxoCFM6MaN4IkBWCoOFMHoK7U4gVOwio3cURBUlHN5wlITwcyvktYbsCQQDswRYqJDBJ5tF412yy8RpF0glJRVM2FAgG0zz8bBvEYJMRVSVi9+Q1u+cFgIPvHDpkaOEezLq+pR3uBGKJ92KhAkBm3n5g+UDsEUN/sYFl/36E0JAjEkkZCxk90ei9C8CJUPAcB2QDf1gN8++DII68afLLld0jVVi+yVv1n1GiTlfrAkEAhrCCj47u+dwap4jHCjYoIDiRl+GcqVNUDa33MBPA6EOY529tSZSFfBxeHb8zT8DbZ2xTRlZqlzMQh+xustbOgQJBAJSq6ioVUR8YwYMl0VD4svuZiuv6aAu2P1BK3f/ftbPyDPm3SKn3TV0/Rpe3KJO1Di2G+8gXyR8tge6Dm3RAdoU=";
// 刚才我们获得的加密数据,一般通过各种传输途径接收到
String encryptReceiveMsg = "dBz/nSJ+jK13dhEhNZOeBcMgQjJfauWP9xl0OLYKiuhKOzYbI+zOezyM1PhHqTvl3hjaTf+wzpzUd+2p75v4Zn8sxSmRw8CIzXTtY/4g3v94cdZbvTfWe+snLXt7qTMdK9grrBqSvBhp/JsOPhd336h/lo77mYd0XEUNJhIFyl0=";
try {
// 把私钥字符串转换成对象
byte[] privateKeyBy = Base64.getDecoder().decode(privateKeyStr.getBytes());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBy));
// 同样的,可以固化cipherPrivate ,但是不能固化cipherPrivate,因为它不是线程安全的
Cipher cipherPrivate = Cipher.getInstance("RSA");
// 设置为解密模式并设置私钥
cipherPrivate.init(Cipher.DECRYPT_MODE, privateKey);
// 进行解密
byte[] decryptByte = cipherPrivate.doFinal(Base64.getDecoder().decode(encryptReceiveMsg));
// 转换成字符串
String receiveMsg = new String(decryptByte, "UTF-8");
System.out.println("解密后的数据:" + receiveMsg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
得到解密结果:
解密后的数据:你好呀!