非对称技术栈实现AES加密解密
正如前面的一篇文章所述,https协议的SSL层是实现在传输层之上,应用层之下,也就是说在应用层上看到的请求还是明码的,对于某些场景下要求这些http请求参数是非可读的,这就要求在前端和后端不同的技术栈上完成信息的加密解密。当然我们通常完成这样专业的功能都会考虑使用相应的框架或者程序库来完成功能,前端或者NodeJS平台通常是JavaScript语言,JavaScript主流的加密解密库分别是SjclJS和CryptoJS, 本文以CryptoJS为例进行讨论。另外在此处多提一句,JavaScript ES6标准已经完成了,现在的JavaScript已经不是当年的JavaScript了,Java该有的JavaScript也全有了,JavaScript作为平台,作为一种严谨大项目开发的语言的日子已经不远了,前几天看到thoughtwork已经把ES6列为了Adopt, 虽然浏览器还没有完全支持,现在使用Babel已经可以写ES6代码了,对了,ES6以后JavaScript已经支持class, 拉姆达表达式等等nb特性了,现在的JavaScript就是当年的Java,将来估计也是一个平台。
书归正传,如示例所示,JavaScript中需要现在浏览器中引入相应的加密库,然后就可以调用相应的加密代码,另外这个加密库也支持NodeJS平台,也可以用如下方式引入和调用。需要说明的是NodeJS平台下的npm安装包和我们下载的版本是不同的,这两种版本不能混用。
var CryptoJS = require("crypto-js"); // Encrypt var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123'); // Decrypt var bytes = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123'); var plaintext = bytes.toString(CryptoJS.enc.Utf8); console.log(plaintext);
完整代码示例如下所示
数据传输到服务端同样需要加密解密才可以使用,否则得到的就只有乱码,没有业务含义,下面分别以两种主流服务端语言C#和Java来说明,服务端的代码实现。需要说明的是单单实现一种平台上的AES加密算法是简单的只要找到相应的函数库完成调用就可以,但是如果需要完成跨平台,跨技术栈,比如在JavaScript加密,C#解密,或者C#加密,Java解密就有些难度,本文的实现是可以达到跨技术栈的目的。
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; namespace UEncrypt { class UEncrypt { static void Main(string[] args) { String encryptData = Program.Encrypt("Hi There", "AjQ0YQ0MvKKC1uTr", "AjQ0YQ0MvKKC1uTr"); Console.WriteLine(encryptData); String decryptData = Program.Decrypt(encryptData, "AjQ0YQ0MvKKC1uTr", "AjQ0YQ0MvKKC1uTr"); Console.WriteLine(decryptData); Console.Read(); } public static string Encrypt(string toEncrypt, string key, string iv) { byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key); byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv); byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt); RijndaelManaged rDel = new RijndaelManaged(); rDel.Key = keyArray; rDel.IV = ivArray; rDel.Mode = CipherMode.CBC; rDel.Padding = PaddingMode.Zeros; ICryptoTransform cTransform = rDel.CreateEncryptor(); byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); return Convert.ToBase64String(resultArray, 0, resultArray.Length); } public static string Decrypt(string toDecrypt, string key, string iv) { byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key); byte[] ivArray = UTF8Encoding.UTF8.GetBytes(iv); byte[] toEncryptArray = Convert.FromBase64String(toDecrypt); RijndaelManaged rDel = new RijndaelManaged(); rDel.Key = keyArray; rDel.IV = ivArray; rDel.Mode = CipherMode.CBC; rDel.Padding = PaddingMode.Zeros; ICryptoTransform cTransform = rDel.CreateDecryptor(); byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); return UTF8Encoding.UTF8.GetString(resultArray); } } }
Java
public class UEncrypt { public static void main(String args[]) throws Exception { String data = encrypt() System.out.println(data); System.out.println(desEncrypt(data)); } public static String encrypt() throws Exception { try { String data = "Hi There"; String key = "AjQ0YQ0MvKKC1uTr"; String iv = "AjQ0YQ0MvKKC1uTr"; Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); int blockSize = cipher.getBlockSize(); byte[] dataBytes = data.getBytes(); int plaintextLength = dataBytes.length; if (plaintextLength % blockSize != 0) { plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); } byte[] plaintext = new byte[plaintextLength]; System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); byte[] encrypted = cipher.doFinal(plaintext); return new sun.misc.BASE64Encoder().encode(encrypted); } catch (Exception e) { } } public static String desEncrypt( String data ) throws Exception { try { String key = "AjQ0YQ0MvKKC1uTr"; String iv = key; byte[] encrypted1 = new BASE64Decoder().decodeBuffer(data); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); byte[] original = cipher.doFinal(encrypted1); String originalString = new String(original); return originalString; } catch (Exception e) { } } }
总结
本文总结了JavaScript, C#, Java三种平台上的AES加密解密算法实现,完整的实现了跨技术栈的加密解密,可以在NodeJS加密,C#解密,希望对大家有所帮助。