密码学(一)——AES前端和后端的加解密以及对接
最早系统学习密码学的知识是在软考过程中,当时也是半瓶子醋晃悠,我记得最近技术分享中也分享过一些相关的知识,可惜也没有细细分析,老大说要在数据在B/S传输过程中要加密,所以自己就先研究的AES前端和后端的加解密以及对接。这是两个过程:前端加密—传输到后台—后台解密、后台加密—传输—前台解密。
AES的基本要求是,采用对称分组密码体制,密钥长度的最少支持为128、192、256,分组长度128位,算法应易于各种硬件和软件实现
加密模式
AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显,大部分的区别在IV和KEY来计算密文的方法略有区别。具体可参考WIKI的说明。另外,AES分为AES128,AES256等,表示期待秘钥的长度,比如AES256秘钥的长度应该是256/8的32字节,一些语言的库会进行自动截取,让人以为任何长度的秘钥都可以。而这其实是有区别的。
IV的作用
IV称为初始向量,不同的IV加密后的字符串是不同的,加密和解密需要相同的IV,既然IV看起来和key一样,却还要多一个IV的目的,对于每个块来说,key是不变的,但是只有第一个块的IV是用户提供的,其他块IV都是自动生成。
IV的长度为16字节。超过或者不足,可能实现的库都会进行补齐或截断。但是由于块的长度是16字节,所以一般可以认为需要的IV是16字节。
PADDING
AES块加密说过,PADDING是用来填充最后一块使得变成一整块,所以对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为PKCS5, PKCS7, NOPADDING。
加密解密端
对于加密端,应该包括:加密秘钥长度,秘钥,IV值,加密模式,PADDING方式。
对于解密端,应该包括:解密秘钥长度,秘钥,IV值,解密模式,PADDING方式。
前端加解密:
<!DOCTYPEhtml> <html> <head> <title>aes demo</title> <meta charset="utf-8"/> <style> *{margin:0;padding:0} .demo-wrap{width: 400px;height:50px;margin: 50px auto auto auto} </style> <scriptsrc="./rollups/aes.js"></script> <!-- <scriptsrc="./components/pad-zeropadding.js"></script>--> </head> <body> <divclass="demo-wrap"> <input type="text"id="data-ipt"/> <buttononclick="getAES();">AES加密</button> <buttononclick="getDAes();">AES解密</button> <br/> 加密后的数据: <p id ="encrypted"></p> 解密后的数据: <pid="decrypted"></p> </div> <script> function getAesString(data,key,iv){//加密 var key = CryptoJS.enc.Utf8.parse(key); //alert(key); var iv = CryptoJS.enc.Utf8.parse(iv); var encrypted =CryptoJS.AES.encrypt(data,key, { iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); return encrypted.toString(); //返回的是base64格式的密文 } function getDAesString(encrypted,key,iv){//解密 var key = CryptoJS.enc.Utf8.parse(key); var iv = CryptoJS.enc.Utf8.parse(iv); var decrypted =CryptoJS.AES.decrypt(encrypted,key, { iv:iv, mode:CryptoJS.mode.CBC, padding:CryptoJS.pad.Pkcs7 }); returndecrypted.toString(CryptoJS.enc.Utf8); // } function getAES(){ //加密 var data =document.getElementById("data-ipt").value;//明文 var key = "abcdefgabcdefg12"; //密钥 var iv = "abcdefgabcdefg12"; var encrypted =getAesString(data,key,iv); //密文 var encrypted1 =CryptoJS.enc.Utf8.parse(encrypted); document.getElementById("encrypted").innerHTML = encrypted; } function getDAes(){//解密 var encrypted =document.getElementById("encrypted").innerHTML; //密文 var key = "abcdefgabcdefg12"; var iv = "abcdefgabcdefg12"; var decryptedStr =getDAesString(encrypted,key,iv); alert(decryptedStr); document.getElementById("decrypted").innerHTML = decryptedStr; } </script> </body> </html>
吃亏的地方在编码格式的问题上,用 crypto.js加密后的密文是base64格式的,而且解密的数据也必须是base64格式的, 这样才能和后台做对接。
现在来看后台代码:
packagecom.test.aes; importjava.io.UnsupportedEncodingException; importjavax.crypto.Cipher; importjavax.crypto.spec.IvParameterSpec; importjavax.crypto.spec.SecretKeySpec; importorg.apache.commons.codec.binary.Base64; public classAesCBC { public static void main(String[] args)throws UnsupportedEncodingException { Stringcontent="12345678"; Stringkey="abcdefgabcdefg12"; Stringiv="abcdefgabcdefg12"; //加密 byte[ ]encrypted=AES_CBC_Encrypt(content.getBytes(), key.getBytes(), iv.getBytes()); //解密 byte[ ]decrypted=AES_CBC_Decrypt(encrypted, key.getBytes(), iv.getBytes()); System.out.println("解密后:"+byteToHexString(decrypted)); System.out.println(byteToString(decrypted)); } public static String byteToString(byte[ ]byte1){ returnnew String(byte1); } public static byte[] AES_CBC_Encrypt(byte[]content, byte[] keyBytes, byte[] iv){ try{ SecretKeySpec key = newSecretKeySpec(keyBytes, "AES"); Ciphercipher=Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE,key, new IvParameterSpec(iv)); byte[]result=cipher.doFinal(content); return result; }catch (Exception e) { System.out.println("exception:"+e.toString()); } return null; } public static byte[] AES_CBC_Decrypt(byte[]content, byte[] keyBytes, byte[] iv){ try{ SecretKeySpec key = newSecretKeySpec(keyBytes, "AES"); Ciphercipher=Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE,key, new IvParameterSpec(iv)); byte[]result=cipher.doFinal(content); return result; }catch (Exception e) { // TODO Auto-generated catchblock System.out.println("exception:"+e.toString()); } return null; } /** * 字符串装换成base64 * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(Stringkey) throws Exception { returnBase64.decodeBase64(key.getBytes()); } /** *二进制装换成base64 * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[]key) throws Exception { returnnew String(Base64.encodeBase64(key)); } }
前端和后端是分开来做的但是都在AES在线生成器中加密过,得到的都是相同的密文。
AES收获很多,这里可能有很多坑,大家踩一踩,然后交流交流。做到最后老大说用RSA算法,今天研究的是RSA也算有进度,等待分享。
附录
http://www.cnblogs.com/vmax-tam/p/4624032.html
http://blog.csdn.net/chence19871/article/details/27653805
http://blog.csdn.net/vieri_32/article/details/48345023
http://blog.csdn.net/defonds/article/details/42775183
http://blog.csdn.net/cfl20121314/article/details/49749275
http://www.cjjjs.com/paper/xmkf/2016629102258195.aspx
http://www.cjjjs.com/paper/xmkf/201663012403485.aspx
http://www.cnblogs.com/shoneworn/p/5071305.html
以上源码下载
- 上一篇: Web前端密码加密是否有意义?
- 下一篇: 前端加密