前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于JSEntrypt.js加密 Java RSA解密

关于JSEntrypt.js加密 Java RSA解密

作者头像
@派大星
发布2023-06-28 14:22:12
4200
发布2023-06-28 14:22:12
举报
文章被收录于专栏:码上遇见你
关于RSA加密解密的一个案例:

首先Java可以定义一个全局处理的一个类,通过实现RequestBodyAdvice来进行统一接口请求参数处理。实现RequestBodyAdvice后重写一个方法beforeBodyRead

  • 可以通过MethodParameter获取请求的方法,这里可以设置一些白名单等,直接放行之类的操作,主要的一行代码如下:
代码语言:javascript
复制
MethodParameter.getMethod().getName())
  • 在里面可以通过HttpInputMessage获取到body的请求参数。
代码语言:javascript
复制
String encryptedText = IOUtils.toString(inputMessage.getBody(), Charset.defaultCharset());

获取到加密的字符串之后就可以进行解密操作了。我这里首先在全局 调用了一个工具类RSATools,在全局处理的类中就一行代码

代码语言:javascript
复制
encryptedText = RSATools.decrypt(encryptedText, privateKey);

首先解释一下privateKey就是一个私钥,这是你自己生成的RSA加密字符串。 接下来给大家看一下RSATools工具类(有些敏感信息进行了脱敏):这个类大家可以简单扫一眼即可,主要的解密方法我进行了抽取,在下面。

代码语言:javascript
复制
public class RSATools {
	public static final String SIGN_ALGORITHMS = "自己的签名";
	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

	/**
	 * RSA最大加密明文大小
	 */
	private static final int MAX_ENCRYPT_BLOCK = 245;

	/**
	 * RSA最大解密密文大小
	 */
	private static final int MAX_DECRYPT_BLOCK = 256;
		private static final String PRIVATEKEY = "自己的私钥";

	/**
	 * 签名
	 * 
	 * @param content
	 * @param privateKey
	 * @return
	 */
	public static String sign(String content, String privateKey) {
		try {
			PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64Tools.decode2Byte(privateKey));
			KeyFactory keyf = KeyFactory.getInstance("RSA");
			PrivateKey priKey = keyf.generatePrivate(priPKCS8);
			Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
			signature.initSign(priKey);
			signature.update(content.getBytes(DEFAULT_CHARSET));
			byte[] signed = signature.sign();
			return Base64Tools.encode2String(signed);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 验签
	 * 
	 * @param content
	 * @param sign
	 * @param publicKey
	 * @return
	 */
	public static boolean verify(String content, String sign, String publicKey) {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			byte[] encodedKey = Base64Tools.decode2Byte(publicKey);
			PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
			Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
			signature.initVerify(pubKey);
			signature.update(content.getBytes(DEFAULT_CHARSET));
			return signature.verify(Base64Tools.decode2Byte(sign));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	public static PublicKey getPublicKey(String key) throws Exception {
		byte[] keyBytes = Base64Tools.decode2Byte(key);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	public static PrivateKey getPrivateKey(String key) throws Exception {
		byte[] keyBytes = Base64Tools.decode2Byte(key);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}

	public static String getKeyString(Key key) throws Exception {
		byte[] keyBytes = key.getEncoded();
		return Base64Tools.encode2String(keyBytes);
	}

	public static <T> String getSignatureContent(Map<String, T> params) {
		if (params == null) {
			return null;
		}
		StringBuffer content = new StringBuffer();
		@SuppressWarnings({ "rawtypes", "unchecked" })
		List<String> keys = new ArrayList(params.keySet());
		Collections.sort(keys);
		for (int i = 0; i < keys.size(); i++) {
			String key = (String) keys.get(i);
			if (params.get(key) != null) {
				String value = String.valueOf(params.get(key));
				content.append((i == 0 ? "" : "&") + key + "=" + value);
			}
		}
		return content.toString();
	}

	@SuppressWarnings("unchecked")
	public static String getListSignatureContent(@SuppressWarnings("rawtypes") List<Map> mapList) {
		if (mapList == null) {
			return null;
		}
		@SuppressWarnings({ "rawtypes" })
		List<String> listStr = new ArrayList();
		for (Map<String, Object> map : mapList) {
			listStr.add(getSignatureContent(map));
		}
		Collections.sort(listStr);
		return listStr.toString();
	}

	/**
	 * 分段加密
	 */
	public static final String KEY_ALGORITHM = "RSA";

	public static String encrpyt(String content, String publicKeyStr) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(1, getPublicKey(publicKeyStr));
		byte[] bytes = content.getBytes(DEFAULT_CHARSET);
		int inputLen = bytes.length;
		int offSet = 0;
		byte[] cache;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int i = 0;
		// 对数据分段加密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] encryptedData = out.toByteArray();
		out.close();
		return Base64Tools.encode2String(encryptedData);
	}

	/**
	 * 分段解密
	 * 
	 * @param content
	 * @param privateKeyStr
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String content, String privateKeyStr) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr));
		byte[] bytes = Base64Tools.decode2Byte(content);
		int inputLen = bytes.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段解密
		while (inputLen - offSet > 0) {
			//System.out.println("第"+i+"次"+(inputLen - offSet >= MAX_DECRYPT_BLOCK) + " -- " + inputLen+" -- "+offSet+" -- "+MAX_DECRYPT_BLOCK+" -- "+(inputLen - offSet));
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
				offSet += MAX_DECRYPT_BLOCK;
			} else {
				cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
				offSet += (inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		String result = new String(decryptedData);
		result=result.replaceAll("<","《");
		result=result.replaceAll(">","》");
		result=result.replaceAll("\\(","(");
		result=result.replaceAll("\\)",")");
		result=result.replaceAll("!","!");
		result=result.replaceAll("`","·");
		result=result.replaceAll("\\n","n");
		return result;
	}
	public static String decryptTwoBarCode(String content) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(2, getPrivateKey(PRIVATEKEY));
		byte[] bytes = Base64Tools.decode2Byte(content);
		int inputLen = bytes.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段解密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		String result = new String(decryptedData);
		result=result.replaceAll("<","《");
		result=result.replaceAll(">","》");
		result=result.replaceAll("\\(","(");
		result=result.replaceAll("\\)",")");
		result=result.replaceAll("!","!");
		result=result.replaceAll("`","·");
		return result;
	}


}

解密、分段解密的主要方法:

代码语言:javascript
复制
/**
	 * 分段解密
	 * 
	 * @param content
	 * @param privateKeyStr
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String content, String privateKeyStr) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyStr));
		byte[] bytes = Base64Tools.decode2Byte(content);
		int inputLen = bytes.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段解密
		while (inputLen - offSet > 0) {
			//System.out.println("第"+i+"次"+(inputLen - offSet >= MAX_DECRYPT_BLOCK) + " -- " + inputLen+" -- "+offSet+" -- "+MAX_DECRYPT_BLOCK+" -- "+(inputLen - offSet));
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(bytes, offSet, MAX_DECRYPT_BLOCK);
				offSet += MAX_DECRYPT_BLOCK;
			} else {
				cache = cipher.doFinal(bytes, offSet, inputLen - offSet);
				offSet += (inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		String result = new String(decryptedData);
		result=result.replaceAll("<","《");
		result=result.replaceAll(">","》");
		result=result.replaceAll("\\(","(");
		result=result.replaceAll("\\)",")");
		result=result.replaceAll("!","!");
		result=result.replaceAll("`","·");
		result=result.replaceAll("\\n","n");
		return result;
	}

这个就是Java后台的主要方法了。大致说一下我的解密过程: 总结

首先我在全局处理类中实现了RequestBodyAdvice接口,并在重写的beforeBodyRead方法中进行了获取方法、以及方法参数的操作、并且要是方法不在白名单中我就进行了一个解密。调用了工具类RSATools的decrypt方法,传入了获取到的需要解密的字符串,以及私钥。这就是大致的JavaRSA解密的思路,相关代码上面已经站出来了。

接下来主要说一下我前台怎么传输的吧。

  • 首先前台我设置了一个拦截器拦截请求参数,并对其参数使用公钥加密。

主要代码:

代码语言:javascript
复制
let src = JSON.stringify(config.data);
CryptoJS.enc.Utf8.parse(src);
let encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
//公钥加密
var encrypted = encrypt.encryptLong(src);
config.data = encrypted;

这里我使用了jsencrypt.min.js工具类, 并且重写了(或者说新增)它里面的加密方法。 这里说一下为什么要修改这个工具类的加密方法。因为在实际生产环境中,你并不能确定你的参数长度具体有多长。网上相关的案例也都是简单的使用这个工具类jsencrypt.min.js自带的加密方法。这个方法使用过程中如果要是简单的、较短的数据参数的一个提交是没有问题的。但是如果要是数据参数过长的话,后面是解析不出来的。所以我在这里进行了一个修改增强。 主要修改方式你在拦截器的js类中编写即可。 js增强代码:

代码语言:javascript
复制
JSEncrypt.prototype.encryptLong = function (string) {
    var k = this.getKey();
    try {
        var ct = "";
        //RSA每次加密117bytes,需要辅助方法判断字符串截取位置
        //1.获取字符串截取点
        var bytes = new Array();
        bytes.push(0);
        var byteNo = 0;
        var len, c;
        len = string.length;
        var temp = 0;
        for (var i = 0; i < len; i++) {
            c = string.charCodeAt(i);
            if (c >= 0x010000 && c <= 0x10FFFF) {  //特殊字符,如Ř,Ţ
                byteNo += 4;
            } else if (c >= 0x000800 && c <= 0x00FFFF) { //中文以及标点符号
                byteNo += 3;
            } else if (c >= 0x000080 && c <= 0x0007FF) { //特殊字符,如È,Ò
                byteNo += 2;
            } else { // 英文以及标点符号
                byteNo += 1;
            }
            if ((byteNo % 117) >= 114 || (byteNo % 117) == 0) {
                if (byteNo - temp >= 114) {
                    bytes.push(i);
                    temp = byteNo;
                }
            }
        }
        //2.截取字符串并分段加密
        if (bytes.length > 1) {
            for (var i = 0; i < bytes.length - 1; i++) {
                var str;
                if (i == 0) {
                    str = string.substring(0, bytes[i + 1] + 1);
                } else {
                    str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);
                }
                var t1 = k.encrypt(str);
                ct += t1;
            }
            ;
            if (bytes[bytes.length - 1] != string.length - 1) {
                var lastStr = string.substring(bytes[bytes.length - 1] + 1);
                ct += k.encrypt(lastStr);
            }
            return hex2b64(ct);
        }
        var t = k.encrypt(string);
        var y = hex2b64(t);
        return y;
    } catch (ex) {
        console.log(ex);
        return false;
    }
};
function hex2b64(h) {
    var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var b64padchar="=";
    var i;
    var c;
    var ret = "";
    for(i = 0; i+3 <= h.length; i+=3) {
        c = parseInt(h.substring(i,i+3),16);
        ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
    }
    if(i+1 == h.length) {
        c = parseInt(h.substring(i,i+1),16);
        ret += b64map.charAt(c << 2);
    }
    else if(i+2 == h.length) {
        c = parseInt(h.substring(i,i+2),16);
        ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
    }
    while((ret.length & 3) > 0) ret += b64padchar;
    return ret;
}

最后给大家分享一下相关博主的文章,比较有用的,避免踩坑吧。 https://www.jianshu.com/p/621d8f7e2b44 https://blog.csdn.net/qq_37314372/article/details/104520559

前端的加密解密案例:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码上遇见你 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于RSA加密解密的一个案例:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档