前端JS对称加密、解密数据
准备事项:引入jquery.js与crypto-js.js
<script src="jquery-1.8.3.js"></script>
<script src="crypto-js.js"></script>
加密
//AES加密
function encrypt(context) {
var encrypted = '';
if (typeof(context) == 'object') {
context = JSON.stringify(context);
}
var srcs = CryptoJS.enc.Utf8.parse(context);
encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString()
}
解密
// AES解密
function decrypt(context) {
var decrypt = CryptoJS.AES.decrypt(context, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
后端Java对称加密、解密数据
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;
/**
* 对称加密解密AES算法
*
* @author JustryDeng
* @date 2018年7月20日 下午6:12:35
*/
public class AESEncryptAndDecryptUtil {
/** 对应:算法/模式/补码方式 */
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
/** 高级加密标准算法 */
private static final String ALGORITHM = "AES";
/** 字符编码 */
private static final String CHARSET = "utf-8";
/** 必须16位 must be 16 bytes long */
private static final String IV = "A-16-Byte-String";
/**
* key为 [16位字节长度 或 24位字节长度 或者 32位字节长度]的字符串 注: key不要是中文
* 注:我们可以定死key,也可以通过传参来获取传过来的key(本人采用传参的方式,所以这个属性注释掉了)
*/
// private static final String KEY = "A-16-Byte-keyVal";
/**
* 加密
*
* @param context
* 要加密的字符串数据
* @param key
* 秘钥
* @return 加密后的数据字符串
* @date 2018年7月20日 下午6:17:44
*/
public static String encrypt(String context, String key) {
try {
byte[] decode = context.getBytes(CHARSET);
byte[] bytes = createKeyAndIv(decode, Cipher.ENCRYPT_MODE, key);
return Base64.getEncoder().encodeToString(bytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
*
* @param context
* 要解密的字符串数据
* @param key
* 对应的秘钥(不论是前端还是后端加的密,key都要和加密时的一样)
* @return 解密后的数据字符串
* @date 2018年7月20日 下午6:18:35
*/
public static String decrypt(String context, String key) {
try {
Base64.Decoder decoder = Base64.getDecoder();
byte[] decode = decoder.decode(context);
byte[] bytes = createKeyAndIv(decode, Cipher.DECRYPT_MODE, key);
return new String(bytes, CHARSET);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 与cipherFilter方法配合,获取加密/解密后的字节数组
*
* @date 2018年7月20日 下午6:21:34
*/
public static byte[] createKeyAndIv(byte[] context, int opmode, final String key) throws Exception {
byte[] keyArray = key.getBytes(CHARSET);
byte[] iv = IV.getBytes(CHARSET);
return cipherFilter(context, opmode, keyArray, iv);
}
public static byte[] cipherFilter(byte[] context, int opmode, byte[] key, byte[] iv) throws Exception {
Key secretKeySpec = new SecretKeySpec(key, ALGORITHM);
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(opmode, secretKeySpec, ivParameterSpec);
return cipher.doFinal(context);
}
}
后端对称加密、解密主函数测试一下
import com.aspire.util.AESEncryptAndDecryptUtil;
/**
* 以主函数进行测试
*
* @author JustryDeng
* @date 2018年7月20日 下午6:40:05
*/
public class Test {
public static void main(String[] args) {
// 16个 或 24个 或 32个 字节长度 即可(注:不要是中文)
String key = "key0123456789key";
String context = "JustryDeng";
System.out.println("原数据:" + context);
// 加密
String encrypt = AESEncryptAndDecryptUtil.encrypt(context, key);
System.out.println("加密后:" + encrypt);
// 解密
String decrypt = AESEncryptAndDecryptUtil.decrypt(encrypt, key);
System.out.println("解密后:" + decrypt);
}
}
输出结果为
前端JS对称加密、后端JAVA接收并解密数据
先给出后端Controller层的代码示例
package com.aspire.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.aspire.util.AESEncryptAndDecryptUtil;
/**
* 前端对称加密 给 后端加密
*
* @author JustryDeng
* @date 2018年7月20日 下午3:19:44
*/
@RestController
public class EncryptAndDecryptController {
// KEY要与前端加密时保持一致(且:应为:16或24或32字节长度)
private static final String KEY = "A-16-Byte-keyVal";
/**
*
*
* @param encryptedTarget
* 加密后的数据字符串
* @return
* @date 2018年7月20日 下午6:47:28
*/
@RequestMapping("/EncryptAndDecryptTest")
public String test(@RequestParam("encryptedTarget") String encryptedTarget) {
StringBuffer sb = new StringBuffer();
try {
// 调用后端AES加密解密工具类(在上面的示例中以给出)
String decryptTarget = AESEncryptAndDecryptUtil.decrypt(encryptedTarget,KEY);
sb.append(">>>解密前:" + encryptedTarget);
sb.append(">>>解密前的内容长度:" + encryptedTarget.length());
sb.append(">>>加密密钥和解密密钥:" + KEY);
sb.append(">>>解密后:" + decryptTarget);
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
}
再给出前端HTML的测试代码为
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>加密demo</title>
<!--引入jquery与crypto-js-->
<script src="jquery-1.8.3.js"></script>
<script src="crypto-js.js"></script>
<script type="text/javascript">
// 加密秘钥key(注:与后端一致)
var key = CryptoJS.enc.Utf8.parse("A-16-Byte-keyVal");
// 加密辅助参数iv
var iv = CryptoJS.enc.Utf8.parse("A-16-Byte-String");
//AES加密
function encrypt(context) {
var encrypted = '';
if (typeof(context) == 'object') {
context = JSON.stringify(context);
}
var srcs = CryptoJS.enc.Utf8.parse(context);
encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
// AES解密
function decrypt(context) {
var decrypt = CryptoJS.AES.decrypt(context, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
// 将id为encryptContent的输入框数据加密,然后赋值给id为helpInput的输入框
function encryptTransmission() {
var beforeContent = $("#encryptContent").val();
// 调用加密方法
var afterContent = encrypt(beforeContent);
// 将加密后的值放入表单中的输入框里,提交表单,传给后台
$("#helpInput").val(afterContent);
}
</script>
</head>
<body>
<form method="post" action="http://localhost:12345/EncryptAndDecryptTest" onsubmit="return true">
<!--onblur事件监听,失去焦点时,触发事件,进行数据加密-->
加密前:
<input id="encryptContent" onblur="encryptTransmission()" type="text" placeholder="请输入英文状态下的文本内容!">
<br>
加密后:
<input name="encryptedTarget" id="helpInput" type="text">
<br>
<input type="submit" value="提交表单>>>Go">
</form>
</body>
</html>
页面是这样的
提交表单访问后台接口,返回的结果是
由此可见:前端加密,后端解密,成功!
提示1:实际上,秘钥key可以设置为动态的,每次前端要发送加密数据前,先问后端要一 个 key,然后用这个key加密数据并发送到后端;后端使用这个key解密后,再销毁这个 key使其失效。
提示2:再严格一点就是,前后端不仅更换秘钥key,甚至还不停地更换加密方法等。
本人内容参考自菜鸟学堂
代码托管链接https://github.com/JustryDeng/PublicRepository
如有不当之处,欢迎指正
本文已经被收录进《程序员成长笔记(二)》,作者JustryDeng