JavaScript实现AES算法加密和解密
JavaScript的加密和解密用的是google的CryptoJS库。本文以AES/ECB/NoPadding为例展示AES加密和解密的方法。
需要下载CryptoJS库,下载地址如下:
https://github.com/sytelus/CryptoJS
需要引入库文件:
<script src="./CryptoJS-master/rollups/aes.js"></script>
<script src="./CryptoJS-master/components/mode-ecb.js"></script>
<script src="./CryptoJS-master/components/pad-nopadding.js"></script>
加密方法:
function encrypt(str) { var decArray = hexStrToDecArray(str); var wordArray = int8parse(decArray); var encrypted = CryptoJS.AES.encrypt(wordArray, aesKeyBytes(), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); return wordArrayToHexStr(encrypted.ciphertext.words); }
这个方法传入的是十六进制字符串,格式为"AA BB CC DD EE FF";
hexStrToDecArray()方法用来将十六进制字符串转换成十进制数字的数组;
int8parse()方法用来将十进制数字转换成CryptoJS所需要的wordArray数组;
最后,encrypt()方法加密得到的是一个wordArray数组,wordArrayToHexStr()再将其解析成十六进制字符串。
解密方法:
function decrypt(str) { var decArray = hexStrToDecArray(str); var wordArray = int8parse(decArray); var base64Str = CryptoJS.enc.Base64.stringify(wordArray); var decrypted = CryptoJS.AES.decrypt(base64Str, aesKeyBytes(), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); return wordArrayToHexStr(decrypted.words); }
解密方法同加密方法类似,但是CryptoJS.AES.decrypt()方法需要传入Base64格式的加密字符串,因此这里需要先使用CryptoJS.enc.Base64.stringify()方法做一次转换。
以下是完整的Demo代码:
<!DOCTYPE html> <html> <head> <script src="./CryptoJS-master/rollups/aes.js"></script> <script src="./CryptoJS-master/components/mode-ecb.js"></script> <script src="./CryptoJS-master/components/pad-nopadding.js"></script> <script> function encryptText() { var plain = document.getElementById("plain").value; console.log("plain: " + plain); var encrypted = encrypt(plain); console.log("encrypted: " + encrypted); document.getElementById("encrypted").value = encrypted; } function decryptText() { var encrypted = document.getElementById("todecrypt").value; console.log("encrypted: " + encrypted); var decrypted = decrypt(encrypted); console.log("decrypted: " + decrypted); document.getElementById("decrypted").value = decrypted; } // 加解密用到的密钥 function aesKeyBytes() { var key_Int = new Int8Array([65, 144, 48, 53, 18, 52, 86, 120, 131, 116, 124, 139, 237, 203, 169, 135]); var keyBytes = int8parse(key_Int); return keyBytes; } // 十六进制字符串数组,个数如果不足16整数倍则补0 function hexTo16Hex(str) { var diff = 16 - (str.length + 1) / 3 % 16; for(var i = 0; i < diff; i++) { str = str + " 00"; } return str; } // AES加密 function encrypt(str) { var decArray = hexStrToDecArray(str); var wordArray = int8parse(decArray); var encrypted = CryptoJS.AES.encrypt(wordArray, aesKeyBytes(), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); return wordArrayToHexStr(encrypted.ciphertext.words); } // AES解密 function decrypt(str) { var decArray = hexStrToDecArray(str); var wordArray = int8parse(decArray); var base64Str = CryptoJS.enc.Base64.stringify(wordArray); var decrypted = CryptoJS.AES.decrypt(base64Str, aesKeyBytes(), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding }); return wordArrayToHexStr(decrypted.words); } // 构建WordArray对象 function int8parse(u8arr) { var len = u8arr.length; var words = []; for (var i = 0; i < len; i++) { words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8); } return CryptoJS.lib.WordArray.create(words, len); } // 十六进制字符串(空格分割)转成十进制数字的数组 function hexStrToDecArray(str) { var strArray = str.split(" "); var decArray = []; for(var i = 0; i < strArray.length; i++) { decArray.push(parseInt(strArray[i], 16)); } return arrayTo16Array(decArray); } // 十进制数组转成十六进制字符串 function decArrayToHexStr(array) { var hexStr = ""; for(var i = 0; i < array.length; i++) { var str = array[i].toString(16).toUpperCase(); if (str.length < 2) { str = "0" + str; } hexStr = hexStr + str + " "; } return hexStr.substr(0, hexStr.length - 1); } // word类型的十进制数组转成十六进制字符串 function wordArrayToHexStr(array) { var hexStr = ""; for(var i = 0; i < array.length; i++) { var num = array[i]; if (num < 0) { num = array[i] + 0x100000000; } var str = num.toString(16).toUpperCase(); var fullStr = str; if (str.length < 8) { for(var j = 0; j < 8 - str.length; j++) { fullStr = "0" + fullStr; } } hexStr = hexStr + fullStr; } var ret = ""; for(var i = 0; i < hexStr.length; i += 2) { ret = ret + hexStr.substr(i, 2) + " " } return ret.substr(0, ret.length - 1); } // 数组元素个数必须是16的整数倍,不足的在后面补0 function arrayTo16Array(array) { var len = array.length; var distLen = parseInt((array.length - 1) / 16) * 16 + 16; for(var i = array.length; i < distLen; i++) { array[i] = 0; } return array; } </script> </head> <body> <h1>加解密测试</h1> AES128,ECB模式,PaddingModeZeros,不足部分补0 <br> <input id="plain" type="text" style="width:500px; height:20px;"/> <button type="button" onclick="encryptText()">加密</button> <input id="encrypted" type="text" style="width:500px; height:20px;" /> <br> <br> <br> <input id="todecrypt" type="text" style="width:500px; height:20px;"/> <button type="button" onclick="decryptText()">解密</button> <input id="decrypted" type="text" style="width:500px; height:20px;" /> </body> </html>
在浏览器中打开之后效果如下:
输入要加密或解密的字符串,点击加密/解密按钮即可。