RSA加密解密(Java) rsa加密工具类,java

RSA加密解密

一、RSA的原理

1.1、RSA的介绍

RSA加密算法是一种可逆的非对称加密算法,即RSA加密时候用的密钥(公钥)和RSA解密时用的密钥(私钥)不是同一把。基本原理是将两个很大的质数相乘很容易得到乘积,但是该乘积分解质因数却很困难。RSA算法被广泛的用于加密解密和RSA签名/验证等领域。

1.2、RSA算法的速度与安全性

​ 比起AES等其它对称算法来说,RSA运算更为复杂,所以要慢得多。

​ 从安全角度来讲,一般建议RSA密钥长度至少为2048位。世界上还没有任何可靠的攻击RSA算法的方式,如果密钥足够长或者没有密钥,想要RSA解密或者破解RSA解密基本是不可能的。RSA从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。

1.3、RSA存储格式

​ DER是RSA密钥的二进制格式,PEM是DER转码为Base64的字符格式,由于DER是二进制格式,不便于阅读和理解。一般而言,密钥都是通过PEM的格式进行存储的,本工具所选择的RSA密钥格式也就是PEM编码存储的格式。

二、项目中使用

​ 因为网站的代码和js对用户是可见的,如果采用对称加密的话那么用户可以通过看js就知道怎么解密数据了。所以为了保证传输重要数据的安全性,需要非对称加密。js给后台提交的数据用服务端给js提供的公钥加密数据。提交到后台用自己私钥解密数据。服务器给js端返回的数据用js给服务器提供的公钥加密,js用自己持有的私钥解密。这样用户在网页端只能看到一个秘钥。就能保证传输的安全性。

1、Java后端使用
1.1、RSA加密工具类–RSAUtils.Class
import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
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.HashMap;
import java.util.Map;
/**
 * @Author: AhNorth
 * @Desc: RSA工具类
 * @DateTime: 2023/6/15 14:51
 */
public class RSAUtils {
 //随机生成密钥对
 public static Map genKeyPair() {
 // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
 KeyPairGenerator keyPairGen = null;
 try {
 keyPairGen = KeyPairGenerator.getInstance("RSA");
 } catch (NoSuchAlgorithmException e) {
 e.printStackTrace();
 }
 // 初始化密钥对生成器,密钥大小为96-1024位
 assert keyPairGen != null;
 keyPairGen.initialize(1024, new SecureRandom());
 // 生成一个密钥对,保存在keyPair中
 KeyPair keyPair = keyPairGen.generateKeyPair();
 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
 String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
 // 得到私钥字符串
 String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
 // 将公钥和私钥保存到Map
 Map keyMap = new HashMap();
 keyMap.put("publicKey", publicKeyString);	//公钥
 keyMap.put("privateKey", privateKeyString);	//私钥
 return keyMap;
 }
 /** RSA公钥加密
 * @param str 加密字符串
 * @param publicKey 公钥
 * @return 密文
 */
 public static String encrypt(String str, String publicKey) {
 //base64编码的公钥
 byte[] decoded = Base64.decodeBase64(publicKey);
 RSAPublicKey pubKey = null;
 String outStr = null;
 try {
 pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
 Cipher cipher = Cipher.getInstance("RSA");
 cipher.init(Cipher.ENCRYPT_MODE, pubKey);
 outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
 } catch (InvalidKeySpecException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException e) {
 e.printStackTrace();
 }
 //RSA加密
 return outStr;
 }
 /** RSA私钥解密
 * @param str 加密字符串
 * @param privateKey 私钥
 * @return 铭文
 */
 public static String decrypt(String str, String privateKey) {
 //64位解码加密后的字符串
 byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
 //base64编码的私钥
 byte[] decoded = Base64.decodeBase64(privateKey);
 RSAPrivateKey priKey = null;
 //RSA解密
 Cipher cipher = null;
 String outStr = null;
 try {
 priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
 cipher = Cipher.getInstance("RSA");
 cipher.init(Cipher.DECRYPT_MODE, priKey);
 outStr = new String(cipher.doFinal(inputByte));
 } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
 e.printStackTrace();
 }
 return outStr;
 }
}
2.2、初始化秘钥

​ 编写获取秘钥接口,前端随机生成uuid并传递给后端,后端初始化密钥对,公钥传递给前端用于加密,私钥保存到redis或本地缓存中方便解密。

/**
 * Desc: 获取公钥
 * @param uuid
 * @return: java.lang.String
 */
@GetMapping("/key")
public Result publicKey(@RequestParam String uuid){
 try {
 //初始化公钥私钥对
 Map keyMap = RSAUtils.genKeyPair();
 String publicKey = keyMap.get("publicKey");
 String privateKey = keyMap.get("privateKey");
 //保存私钥到缓存
 if(open){
 String key = RedisKeys.getPrivateKey(uuid);
 redisUtils.set(key, privateKey, 300);
 }else {
 localCache.put("privateKey" + uuid, privateKey);
 }
 return publicKey;
 } catch (Exception e) {
 e.printStackTrace();
 }
 return null;
}

2.3、解密

​ 根据获取公钥的uuid从缓存中获取对应的私钥后使用工具类中的方法解密即可。

/**
 * Desc: 解密
 * @param uuid
 * @param data	加密后的数据
 * @return: java.lang.String
 */
public static String getDecryptStr(uuid, data){
 String privateKey = null;
 if(open){
 uuid = RedisKeys.getPrivateKey(uuid);
 privateKey = (String)redisUtils.get(uuid);
 //删除Redis中的私钥
 if(privateKey != null){
 redisUtils.delete(uuid);
 }
 }else {
 privateKey = localCache.getIfPresent("privateKey" + uuid);
 //删除缓存中的私钥
 if(privateKey != null){
 localCache.invalidate("privateKey" + uuid);
 }
 }
 	//解密
 String str = null;
 try {
 str = RSAUtils.decrypt(data, privateKey);
 } catch (Exception e) {
 System.out.println("解密错误");
 e.printStackTrace();
 }
 return str;
}
2、Vue前端使用

​ jsencrypt和encryptlong都是rsa加密,加密的对象一定要是字符串。 简单数据用前者,如果加密的是对象并且数据还挺多的,比如含有token 用后者。

2.1、引入依赖
npm install jsencrypt --save 
npm install encryptlong --save
2.2、RSA加密工具类–rsa.js
/* 产引入jsencrypt实现数据RSA加密 */
import JSEncrypt from 'jsencrypt' // 处理长文本数据时报错 jsencrypt.js Message too long for RSA
/* 产引入encryptlong实现数据RSA加密 */
import Encrypt from 'encryptlong' // encryptlong是基于jsencrypt扩展的长文本分段加解密功能。
/**
 * JSEncrypt加密
 * @param data 数据
 * @param publicKey 公钥
 * @returns {string}
 */
export function rsaPublicData(data, publicKey) {
 const jsencrypt = new JSEncrypt()
 jsencrypt.setPublicKey(publicKey)
 // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
 return jsencrypt.encrypt(data)
}
/**
 * JSEncrypt解密
 * @param data 数据
 * @param privateKey 私钥
 * @returns {string}
 */
export function rsaPrivateData(data, privateKey) {
 const jsencrypt = new JSEncrypt()
 jsencrypt.setPrivateKey(privateKey)
 // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
 return jsencrypt.encrypt(data)
}
/**
 * encryptlong加密
 * @param data 数据
 * @param publicKey 公钥
 * @returns {string}
 */
export function encrypt(data, publicKey) {
 const encryptor = new Encrypt()
 encryptor.setPublicKey(publicKey)
 // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
 return encryptor.encryptLong(data)
}
/**
 * encryptlong解密
 * @param data 数据
 * @param privateKey 私钥
 * @returns {string}
 */
export function decrypt(data, privateKey) {
 const encryptor = new Encrypt()
 encryptor.setPrivateKey(privateKey)
 // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
 return encryptor.decryptLong(data)
}
2.3、生成uuid

​ 前端生成uuid传给后端,在初始化密钥对的时候使用该uuid作为key将私钥保存到缓存中,登录时也需要上传该uuid使后端可以从缓存中获取到对应的秘钥。

2.4、加密

​ 获取到公钥后根据公钥加密后传输给后端。

const password = encrypt(this.password.toString(), publicKey)

感谢大家的观看。

作者:JfZaCc原文地址:https://blog.csdn.net/zhenlanxiao20/article/details/142182623

%s 个评论

要回复文章请先登录注册