首先需要明确的是RSA的密钥对不能手动指定,需要通过代码系统生成
接下来我们来介绍下生成密钥对
package com.weiyuan.test; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; public class RSACrypt { public static void main(String[] args) { //生成RSA的密钥对 try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); //将生成的公钥和私钥转换成字符串,为了防止乱码采用base64编码 String publicKeyStr = Base64Util.encode(publicKey.getEncoded()); String privateKeyStr = Base64Util.encode(privateKey.getEncoded()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
接下来我们来实现私钥加密和公钥加密的代码
package com.weiyuan.test; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; public class RSACrypt { public static void main(String[] args) { //生成RSA的密钥对 try { String input ="我爱黑马程序"; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); encryptByPrivateKey(privateKey, input); encryptByPublicKey(publicKey, input); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 接下来我们来实现私钥加密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String encryptByPublicKey(PublicKey publicKey,String input) throws Exception, NoSuchPaddingException{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] doFinal = cipher.doFinal(input.getBytes()); //将加密之后的数据进行base64编码,输出 String result = Base64Util.encode(doFinal); return result; } /** * 接下来我们来实现公钥加密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String encryptByPrivateKey(PrivateKey privateKey,String input) throws Exception, NoSuchPaddingException{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); byte[] doFinal = cipher.doFinal(input.getBytes()); //将加密之后的数据进行base64编码,输出 String result = Base64Util.encode(doFinal); return result; } }
上面的代码存在一个问题。对于RSA算法对于输入的原文长度不能超过117个字节,数据长度过长,我们应该采用分段加密的方式
javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:337) at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:382) at javax.crypto.Cipher.doFinal(Cipher.java:2087) at com.weiyuan.test.RSACrypt.encryptByPrivateKey(RSACrypt.java:63) at com.weiyuan.test.RSACrypt.main(RSACrypt.java:22)
我们来看下面的代码
package com.weiyuan.test; import java.io.ByteArrayOutputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; public class RSACrypt { public static void main(String[] args) { //生成RSA的密钥对 try { String input ="我爱黑马程序文件和将服务很纠结二十夫君今何伤方法反倒是积极上进发动机号的时间较慢的方式结算单夫君今何伤的今君得所附渐觉受东风基金会的深井冻痕生解决好多说几句话的实践活动睡觉觉"; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); encryptByPrivateKey(privateKey, input); encryptByPublicKey(publicKey, input); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 接下来我们来实现私钥加密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String encryptByPublicKey(PublicKey publicKey,String input) throws Exception, NoSuchPaddingException{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); //这里要采用分段加密的方式对数据进行加密 //RSA分段加密最大的分段大小是117个字节 //加密的偏移量 int offset = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream(); //判断加密数据是否结束 while(input.getBytes().length - offset > 0){ //判断是否到了最后一个分段块 if(input.getBytes().length - offset > 117){ buffer = cipher.doFinal(input.getBytes(),offset,117); bOutputStream.write(buffer); offset = offset +117; }else{ //说明最后一个分段快 buffer = cipher.doFinal(input.getBytes(),offset,input.getBytes().length - offset); bOutputStream.write(buffer); offset = input.getBytes().length; } } //将加密之后的数据进行base64编码,输出 String result = Base64Util.encode(bOutputStream.toByteArray()); return result; } /** * 接下来我们来实现公钥加密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String encryptByPrivateKey(PrivateKey privateKey,String input) throws Exception, NoSuchPaddingException{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); //这里要采用分段加密的方式对数据进行加密 //RSA分段加密最大的分段大小是117个字节 //加密的偏移量 int offset = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream(); //判断加密数据是否结束 while(input.getBytes().length - offset > 0){ //判断是否到了最后一个分段块 if(input.getBytes().length - offset > 117){ buffer = cipher.doFinal(input.getBytes(),offset,117); bOutputStream.write(buffer); offset = offset +117; }else{ //说明最后一个分段快 buffer = cipher.doFinal(input.getBytes(),offset,input.getBytes().length - offset); bOutputStream.write(buffer); offset = input.getBytes().length; } } //将加密之后的数据进行base64编码,输出 String result = Base64Util.encode(bOutputStream.toByteArray()); return result; } }
接下来我们来使用分段解密的步骤
特别需要强调的是对于RSA分段加密的最大分组快的大小是117个字节,分段解密的最大块大小是128个字节
我们来看下面的代码
package com.weiyuan.test; import java.io.ByteArrayOutputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; public class RSACrypt { public static void main(String[] args) { //生成RSA的密钥对 try { String input ="我爱黑马程序文件和将服务很纠结二十夫君今何伤方法反倒是积极上进发动机号的时间较慢的方式结算单夫君今何伤的今君得所附渐觉受东风基金会的深井冻痕生解决好多说几句话的实践活动睡觉觉"; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); String encryptByPublicKey = encryptByPublicKey(publicKey, input); String privateKey2 = decryptByPrivateKey(privateKey, encryptByPublicKey); System.out.println(privateKey2); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 接下来我们来实现私钥加密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String encryptByPublicKey(PublicKey publicKey,String input) throws Exception, NoSuchPaddingException{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); //这里要采用分段加密的方式对数据进行加密 //RSA分段加密最大的分段大小是117个字节 //加密的偏移量 int offset = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream(); //判断加密数据是否结束 while(input.getBytes().length - offset > 0){ //判断是否到了最后一个分段块 if(input.getBytes().length - offset > 117){ buffer = cipher.doFinal(input.getBytes(),offset,117); bOutputStream.write(buffer); offset = offset +117; }else{ //说明最后一个分段快 buffer = cipher.doFinal(input.getBytes(),offset,input.getBytes().length - offset); bOutputStream.write(buffer); offset = input.getBytes().length; } } //将加密之后的数据进行base64编码,输出 String result = Base64Util.encode(bOutputStream.toByteArray()); return result; } /** * 接下来我们来实现公钥加密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String encryptByPrivateKey(PrivateKey privateKey,String input) throws Exception, NoSuchPaddingException{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, privateKey); //这里要采用分段加密的方式对数据进行加密 //RSA分段加密最大的分段大小是117个字节 //加密的偏移量 int offset = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream(); //判断加密数据是否结束 while(input.getBytes().length - offset > 0){ //判断是否到了最后一个分段块 if(input.getBytes().length - offset > 117){ buffer = cipher.doFinal(input.getBytes(),offset,117); bOutputStream.write(buffer); offset = offset +117; }else{ //说明最后一个分段快 buffer = cipher.doFinal(input.getBytes(),offset,input.getBytes().length - offset); bOutputStream.write(buffer); offset = input.getBytes().length; } } //将加密之后的数据进行base64编码,输出 String result = Base64Util.encode(bOutputStream.toByteArray()); return result; } /** * 接下来我们来实现私钥解密 * @throws NoSuchPaddingException * @throws Exception * * */ public static String decryptByPrivateKey(PrivateKey privateKey,String input) throws Exception, NoSuchPaddingException{ // 传入的参数是经过base64加密的数据,首先需要对数据进行base64解密 byte[] inputCode = Base64Util.decode(input); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); //这里要采用分段加密的方式对数据进行加密 //RSA分段解密最大的分段大小是128个字节 //加密的偏移量 int offset = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream bOutputStream = new ByteArrayOutputStream(); //判断加密数据是否结束 while(inputCode.length - offset > 0){ //判断是否到了最后一个分段块 if(inputCode.length - offset > 128){ buffer = cipher.doFinal(inputCode,offset,128); bOutputStream.write(buffer); offset = offset +128; }else{ //说明最后一个分段快 buffer = cipher.doFinal(inputCode,offset,inputCode.length - offset); bOutputStream.write(buffer); offset = inputCode.length; } } //将加密之后的数据进行base64编码,输出 String result = bOutputStream.toString(); return result; } }