前言
由于在银行方面工作对数据安全性要求比较高,需要对前后端通信的数据进行加密,因此编写一个简易的RSA加密算法工具类,可以提高前后端传送数据时的安全性。再次罗列下来,希望自己能有一个更好的理解以及帮助到有需要的小伙伴!有问题的小伙伴可以底部留言,我抽空都会帮忙解答一下,一起加油,共同进步!
一、第一步使用generatorKeyPair产生公私钥
首先创建generatorKeyPair对象(传入要加密的算法)并初始化(传入加密位数),使用其产生keyPair,接着从其其中取出公私钥,最后放到map中进行打包返回。 /**
* 通过KeyPairGenerator产生公私钥
* @return
* @throws NoSuchAlgorithmException
*/
public static Map<String ,Object> generetorKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(INITIALIZE_LENGTH);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
HashMap<String, Object> map = new HashMap<>();
map.put("RSAPublicKey",rsaPublicKey);
map.put("RSAPrivateKey",rsaPrivateKey);
return map;
}
二、取出公私钥字符串
手动创建两个方法,分别对公私钥进行base64加密字符串(此处采用 java.util.Base64或者commons.codec下的Base64都是可以的),有效提高公私钥的安全性。
/**
* 拿到RSA公钥字符串
* @param map
* @return
*/
public static String getRSAPublicKey(Map<String ,Object> map) {
Key rsaPublicKey = (Key) map.get(PUBLIC_KEY);
return Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded());
}
/**
*拿到RSA私钥字符串
* @param map
* @return
*/
public static String getRSAPriateKey(Map<String ,Object> map) {
Key rsaPrivateKey = (Key) map.get(PRIVATE_KEY);
return Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded());
}
三、加解密算法
通过Cipher加解密类实现RSA的加密解密,加密和解密的过程类似,是一个可逆的过程。加密公钥采用的是X509EncodedKeySpec 产生一个实例作为参数传入KeyFactory中产生一个公钥。后面直接把公钥以及数据作为参数传入Cipher中即可实现加密。这里如果需要加密的数据长度较小可以采用一次加密。否则可以采用分段加密,代码中有详细解释,这里不多做阐述。解密的过程类似,但采用PKCS8EncodedKeySpec 产生实例,并把其传入KeyFactory中产生私钥,下面解密与加密类似可以一次性解密就直接解密,否则就分段解密。
/**
* 使用公钥进行加密
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static byte[] encryptByPublic( byte[] data,String publicKey ) throws Exception {
byte[] decode = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE,publicK);
//如果加密明文长度小于规定的最大长度,如下直接加密就好,否则需要分段加密
//cipher.doFinal(data);
//以下为分段加密
int length = data.length;
int i=0;
int offset=0;
byte[] cache = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (length-offset>0) {
if (length-offset>MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK);
}else {
cache = cipher.doFinal(data,offset,length-offset);
}
baos.write(cache,0,cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptData = baos.toByteArray();
baos.close();
return encryptData;
}
/**
* 使用私钥进行解密
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey( byte[] data,String privateKey ) throws Exception {
byte[] decode = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey publicK = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE,publicK);
//如果解密明文长度小于规定的最大长度,如下直接解密就好,否则需要分段解密
//cipher.doFinal(data);
//以下为分段解密
int length = data.length;
int i=0;
int offset=0;
byte[] cache = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (length-offset>0) {
if (length-offset>MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(data, offset, MAX_DECRYPT_BLOCK);
}else {
cache = cipher.doFinal(data,offset,length-offset);
}
baos.write(cache,0,cache.length);
i++;
offset = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptData = baos.toByteArray();
baos.close();
return decryptData;
}
该处使用的url网络请求的数据。
四、测试(附全码)
下面我们简单测试一下,随便传句话,试下效果。各位小伙伴们,如下所示:
package com.trs.util;
import jdk.nashorn.internal.runtime.RewriteException;
import org.omg.CORBA.PUBLIC_MEMBER;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* Demo class
*一个简易版本的RSA加密算法的实现
* @author crazy-water
* @date 10/21/2021 6:43 PM
*/
public class RSAUtil {
//加密算法
public static final String KEY_ALGORITHM = "RSA";
//RSA公钥
public static final String PUBLIC_KEY = "RSAPublicKey";
//RSA私钥
public static final String PRIVATE_KEY = "RSAPrivateKey";
//1024位最大加密长度
public static final int MAX_ENCRYPT_BLOCK = 117;
//1024位最大解密长度
public static final int MAX_DECRYPT_BLOCK = 128;
//加密位数
public static final int INITIALIZE_LENGTH = 1024;
/**
* 通过KeyPairGenerator产生公私钥
* @return
* @throws NoSuchAlgorithmException
*/
public static Map<String ,Object> generetorKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(INITIALIZE_LENGTH);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
HashMap<String, Object> map = new HashMap<>();
map.put("RSAPublicKey",rsaPublicKey);
map.put("RSAPrivateKey",rsaPrivateKey);
return map;
}
/**
* 拿到RSA公钥字符串
* @param map
* @return
*/
public static String getRSAPublicKey(Map<String ,Object> map) {
Key rsaPublicKey = (Key) map.get(PUBLIC_KEY);
return Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded());
}
/**
*拿到RSA私钥字符串
* @param map
* @return
*/
public static String getRSAPriateKey(Map<String ,Object> map) {
Key rsaPrivateKey = (Key) map.get(PRIVATE_KEY);
return Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded());
}
/**
* 使用公钥进行加密
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static byte[] encryptByPublic( byte[] data,String publicKey ) throws Exception {
byte[] decode = Base64.getDecoder().decode(publicKey);
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE,publicK);
//如果加密明文长度小于规定的最大长度,如下直接加密就好,否则需要分段加密
//cipher.doFinal(data);
//以下为分段加密
int length = data.length;
int i=0;
int offset=0;
byte[] cache = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (length-offset>0) {
if (length-offset>MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK);
}else {
cache = cipher.doFinal(data,offset,length-offset);
}
baos.write(cache,0,cache.length);
i++;
offset = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptData = baos.toByteArray();
baos.close();
return encryptData;
}
/**
* 使用私钥进行解密
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey( byte[] data,String privateKey ) throws Exception {
byte[] decode = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey publicK = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE,publicK);
//如果解密明文长度小于规定的最大长度,如下直接解密就好,否则需要分段解密
//cipher.doFinal(data);
//以下为分段解密
int length = data.length;
int i=0;
int offset=0;
byte[] cache = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (length-offset>0) {
if (length-offset>MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(data, offset, MAX_DECRYPT_BLOCK);
}else {
cache = cipher.doFinal(data,offset,length-offset);
}
baos.write(cache,0,cache.length);
i++;
offset = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptData = baos.toByteArray();
baos.close();
return decryptData;
}
/**
* 主函数测试
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
Map<String, Object> map = generetorKeyPair();
String rsaPublicKey = getRSAPublicKey(map);
String rsaPriateKey = getRSAPriateKey(map);
String oldData = "各位小伙伴,新的一天继续加油哦";
System.out.println("加密前的数据-----------"+oldData);
byte[] encryptData = encryptByPublic(oldData.getBytes(), rsaPublicKey);
byte[] decryptData = decryptByPrivateKey(encryptData, rsaPriateKey);
System.out.println("解密后的数据-----------"+new String(decryptData));
}
}
测试结果图,如图所见,结果正确无误。小伙伴们,星光不负赶路人,抓紧搞起来吧。