1. cryptojs是什么?
有时候项目涉及到的敏感数据比较多,为了信息安全,我们常常需要对一些数据进行接口加密处理,如编码、将明文转化为暗文、加密比对、AES + BASE64 算法加密等。
接下来我们就分别说一下 CryptoJS 常用的一些方法。
CryptoJS是一个JavaScript的加解密的工具包。它支持多种的算法:MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。
1.1. 为什么要编码
由于一些网络通讯协议的限制, 又或者是出于信息加密的目的, 我们就需要将原信息转换为base64编码,然后才能进行传输.例如,发送某些含有 ASCII 码表中0到31之间的控制字符的数据。
window.btoa 对字符串进行 base64编码(注意不能编码中文);
winodw.atob 对 base64字符串 进行解码(对于包含中文的 base64编码,不能正确解码);
通常的方法是通过 window.btoa() 方法对源数据进行编码, 然后接收方使用 window.atob() 方法对其进行解码, 从而得到原数据。但是这种方法存在的问题是:window.btoa() 不支持中文, window.atob() 转换含有中文的 base64编码 的时候中文部分会变为乱码。另一个存在的问题是解码github的readme数据的时候也是乱码。经过查找相关资料发现了 Base64的编码与解码转的最优方案:
1.2.单向散列函数
在网站项目中,有时我们需要对传给后端的数据,比如 token 等进行加密处理。本文是对几种常见的前端加密方法,以及如何使用开源的加密库 crypto-js、JSEncrypt 来实现它们的分享。
又称为消息摘要算法,是不可逆的加密算法,即对明文进行加密后,无法通过得到的密文还原回去得到明文。一般所谓的比如 MD5解密,其实是不断的尝试用不同的明文进行加密,直到得到的加密结果一致。
常见的单项散列函数有 MD5、SHA1、SHA256、SHA512 ,以及它们之前加上 Hmac(Keyed-hash message authentication codes) 后的 HmacMD5、HmacSHA1 等。下面以 MD5 为例重点介绍,其它几种则可以举一反三,不多赘述
1.3. MD5
MD5 长度固定,不论输入的内容有多少字节,最终输出结果都为 128 bit,即 16 字节。这也就解释了为什么 MD5 以及其它单向散列函数是不可逆的 —— 输出定长代表会有数据丢失。
通常,我们可以用 16 进制字面值来表示它,每 4 bit 以 16 进制字面值显示,得到的是一个长度为 32 位的字符串。注意,MD5 等单向散列函数具有高度的离散性,意思是只要输入的明文不一样,得到的结果就完全不一样,哪怕是仅仅多了一个空格。
1.4. 使用场景
MD5 有下面几种使用场景:
可以用来做密码的保护。比如可以不直接存储用户的密码,而是存储密码的 MD5 结果。但是现在一般认为用 MD5 来做加密是不太安全的,更多是利用 MD5 的高度离散性特点,用它来做数字签名、完整性校验,云盘秒传等;
1.5. 数字签名
完整性校验。比如前端向后端传输一段非常大的数据,为了防止网络传输过程中丢失数据,可以在前端生成一段数据的 MD5 一同传给后端,这样后端接收完数据后再计算一次 MD5,就知道数据是否完整了。
2. crypto-js 进行 MD5 加密
2.1.引用
<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
2.1.代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>cryptojs</title>
<meta content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<script type="text/javascript" src="../static/helper/crypto-js.js"></script>
<script type="text/javascript" src="../static/js/vconsole.min.js"></script>
<script>
var vc = new VConsole()
</script>
</head>
<body>
<section class="base-title-layout2">
<div class="base-title-bar2">
<span class="base-title-back" onclick="history.go(-1)">
<img src="../img/icon/icon_back.png"/>
</span>
<h1>cryptojs</h1>
<span class="base-title-back">
</span>
</div>
</section>
<div class="base-main-menu-layout">
</div>
<script type="text/javascript" src="../js/page-cryptojs.js"></script>
</body>
</html>
<script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
2.1.代码
/*初始化方法*/
$(function () {
//初始化数据
initData()
});
/**
* 初始化数据
*/
function initData() {
var pwd = "111111";
console.log('-----原密码-----', pwd);
console.log('-----加密后-----', myEncrypt(pwd));
console.log('-----解密后-----', myDecrypt(myEncrypt(pwd)));
console.log("加密结果==",myEncrypt2('Hkxzx@2023'))
}
//加密方法
function myEncrypt2(word) {
var keyStr="ab489fe897hh78ha"
// 十六位十六进制数作为密钥
const key = CryptoJS.enc.Utf8.parse(keyStr);
const srcs = CryptoJS.enc.Utf8.parse(word);
return CryptoJS.AES.encrypt(srcs, key,
{ mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }).toString();
}
// 十六位十六进制数作为密钥
const key = CryptoJS.enc.Latin1.parse("adm-ui-encodeKey");
// 十六位十六进制数作为密钥偏移量
const iv = CryptoJS.enc.Latin1.parse('adm-ui-encodeKey');
/**
* 解密方法
* @param word
* @returns {string}
*/
function myDecrypt(word) {
let encryptedHexStr = CryptoJS.enc.Base64.parse(word)
let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
let decrypt = CryptoJS.AES.decrypt(srcs, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
/**
* 加密方法
* @param word
* @returns {string}
*/
function myEncrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(word);
let encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}