〇、AES 简介
AES 的全称是 Advanced Encryption Standard,意思是高级加密标准。它的出现主要是为了取代 DES(Data Encryption StandardData Encryption Standard)加密算法的,因为我们都知道 DES 算法的密钥长度是 56Bit,因此算法的理论安全强度是 2 的 56 次方。虽然出现了 3DES 的加密方法,但由于它的加密时间是 DES 算法的 3 倍多,64Bit 的分组大小相对较小,所以还是不能满足人们对安全性的要求。于是 1997 年 1 月 2 号,美国国家标准技术研究所宣布希望征集高级加密标准,最终经过安全性分析、软硬件性能评估等严格的步骤,Rijndael 算法获胜。加密算法的要求是:
- 分组大小为 128 位的分组密码。
- 必须支持三种密码标准:128 位、192 位和 256 位。
- 比提交的其他算法更安全。
- 在软件和硬件实现上都很高效。
AES 密码与分组密码 Rijndael 基本上完全一致,Rijndael 分组大小和密钥大小都可以为 128 位、192 位和256 位。然而 AES 只要求分组大小为 128 位,因此只有分组长度为 128Bit 的 Rijndael 才称为 AES 算法。密钥长度为 192 位和 256 位的处理方式和 128 位的处理方式类似,只不过密钥长度每增加 64 位,算法的循环次数就增加 2 轮,128 位循环 10 轮、192 位循环 12 轮、256 位循环 14 轮。
关于 AES 算法参考: 密码学基础:AES加密算法
AES 其中常用的模式就是 ECB 和 CBC,优缺点如下:
ECB 模式(适合加密小消息)(Electronic Code Book:电子密码本)
优点:
- 简单;
- 有利于并行计算;
- 误差不会被传送;
- 不需要初始化向量 IV
缺点:
- 不能隐藏明文的模式;
- 可能对明文进行主动攻击。
CBC 模式:(适合机密比较长的消息)(Cipher Block Chaining:加密块链)
优点:
- 不容易主动攻击,安全性好于 ECB;
- 适合传输长度长的报文,是 SSL、IPSec 的标准。
缺点:
- 不利于并行计算;
- 误差传递;
- 需要初始化向量 IV
注意:另外还有两种模式(OFB-Output FeedBack-输出反馈、CFB-Cipher FeedBack Mode-加密反馈),本文不再介绍。
加密模式参考:分组对称加密模式:ECB/CBC/CFB/OFB缺CTR
一、C# 代码实现
注意:本示例输出的是 Base64 编码格式结果,若需其他格式,可在最后密文输出时,修改Convert.ToBase64String()
方法,然后解密时修改Convert.FromBase64String()
方法。
// 测试 (注意:密钥的长度必须是 16/24/32)
string miwen16 = SecurityAES.AesEncrypt("TestString", "1111122222333334"); // rNSr6EVnwFlIbr43jm5pvQ==
string miwen24 = SecurityAES.AesEncrypt("TestString", "111112222233333444445555"); // YDYadzDDM5b6EVfi3EUVIQ==
string miwen32 = SecurityAES.AesEncrypt("TestString", "11111222223333344444555556666677"); // K+fDhtmqpkwWZL4kByCLFQ==
///
/// AES 加密
///
/// 待加密字符串
/// 密钥
///
public static string AesEncrypt(string aeseninstr, string secretkey)
{
int[] digitlist = { 16, 24, 32 };
if (string.IsNullOrEmpty(aeseninstr) ||string.IsNullOrEmpty(secretkey)|| Array.IndexOf(digitlist, secretkey.Length)
/// AES 解密
///
/// 密文
/// 密钥
///
public static string AesDecrypt(string aesdeinstr, string secretkey)
{
int[] digitlist = { 16, 24, 32 };
if (string.IsNullOrEmpty(aesdeinstr) || string.IsNullOrEmpty(secretkey) || Array.IndexOf(digitlist, secretkey.Length)
二、js 语言实现
1、通过引用 crypto-js 实现(操作简单,推荐使用)
// 引入 crypto-js
// npm 方式
> npm install crypto-js
// 调用方法 message() 查看结果
// 注意:加解密的编码类型需相同,本示例统一采用 UTF-8
function message(){
outdata_value = AES_ECB_ENCRYPT("TestString", "1111122222333334");
alert(outdata_value)
console.log("outdata_value-aes_encrypt:", outdata_value);
outdata_value = AES_ECB_DECRYPT(outdata_value, "1111122222333334");
alert(outdata_value)
console.log("outdata_value-aes_decrypt:", outdata_value);
}
// 加密
function AES_ECB_ENCRYPT(text, secretKey) {
var keyHex = CryptoJS.enc.Utf8.parse(secretKey);
var messageHex = CryptoJS.enc.Utf8.parse(text);
var encrypted = CryptoJS.AES.encrypt(text, keyHex, {
"mode": CryptoJS.mode.ECB,
"padding": CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
// 解密
function AES_ECB_DECRYPT(textBase64, secretKey) {
var keyHex = CryptoJS.enc.Utf8.parse(secretKey);
var decrypt = CryptoJS.AES.decrypt(textBase64, keyHex, {
"mode": CryptoJS.mode.ECB,
"padding": CryptoJS.pad.Pkcs7
});
return CryptoJS.enc.Utf8.stringify(decrypt);
}
2、纯 js 方法的实现
注意:经测试也是可以用的,但是还需要进一步优化,现只支持待加密字符和密钥均为 16 位。
调用 message() 方法查看效果。
控制台输出:
点击查看 js 语言实现
let outdata_value = "";
let indata_value = "czzj.zfy.acomfei";
let key_value = strtoascii("1111122222333334"); // 49 49 49 49 49 50 50 50 50 50 51 51 51 51 51 52
function message(){
indata_value = stringToHex(indata_value); // 转为 Hex 类型
console.log("indata_value1:",indata_value); // 66 65 69 6e 69 61 6f 6d 79 2e 63 6f 6d 66 65 69
aes_encrypt();
alert(outdata_value) // d1 63 4a fa 0c da da d1 14 e0 fc 63 f1 75 02 cf
console.log("outdata_value-aes_encrypt:", outdata_value);
indata_value = outdata_value;
console.log("indata_value2:",indata_value);
aes_decrypt();
console.log("outdata_value-aes_decrypt:",outdata_value); // 63 7a 7a 6a 2e 7a 66 79 2e 61 63 6f 6d 66 65 69
alert(hexCharCodeToStr(outdata_value)); // 将 UTF-8 编码的 Hex 类型转为 string
}
// 将 string 转为 Hex
function stringToHex(str) {
var val = ""
for (var i = 0; i >> 4) & 0x0f;
return vh.toString(16) + (val & 0x0f).toString(16);
}
// convert a 32-bit value to a 8-char hex string
function cvt_hex32(val) {
var str = "";
var i;
var v;
for (i = 7; i >= 0; i--) {
v = (val >>> (i * 4)) & 0x0f;
str += v.toString(16);
}
return str;
}
// convert a two-digit hex value to a number
function cvt_byte(str) {
// get the first hex digit
var val1 = str.charCodeAt(0);
// do some error checking
if (val1 >= 48 && val1 = 65 && val1 = 97 && val1 = 48 && val2 = 65 && val2 = 97 && val2 16) {
window.alert(lbl + " is too long, using the first 16 ASCII characters");
}
// have ASCII data
// 16 characters?
if (str.length >= 16) {
// 16 or more characters
for (i = 0; i 0) {
if ((a & 1) != 0)
res = res ^ b; // "add" to the result
a >>>= 1; // shift a to get next higher-order bit
b = 0x100) {
if ((res & hbit) != 0) // if the high-order bit is set
res ^= modulus; // XOR with the modulus
// prepare for the next loop
hbit >>= 1;
modulus >>= 1;
}
return res;
}
// apply the S-box substitution to the key expansion
function SubWord(word_ary) {
var i;
for (i = 0; i 0) {
if ((exp & 1) != 0)
result = aes_mul(result, val);
// square the value
val = aes_mul(val, val);
// move to the next bit
exp >>= 1;
}
return result;
}
// round key generation
// return a byte array with the expanded key information
function key_expand(key) {
var temp = new Array(4);
var i, j;
var w = new Array(4 * 11);
// copy initial key stuff
for (i = 0; i >> 2);
accumulate_wordarray(" ^ Rcon()=", temp);
}
// word = word ^ temp
for (j = 0; j = 1; round--) {
accumulate_array("Round " + round, state);
state = InvShiftRows(state);
accumulate_array("After InvShiftRows", state);
state = SubBytes(state, S_dec);
accumulate_array("After SubBytes", state);
// display the round key - Transpose due to the way it is stored/used
accumulate_array("Round Key", transpose(w.slice(round * 4 * 4, round * 16 + 16)));
// note here the spec uses 32-bit words, we are using bytes, so an extra *4
state = AddRoundKey(state, w, round * 4 * 4);
accumulate_array("After AddRoundKey", state);
state = InvMixColumns(state);
}
InvShiftRows(state);
accumulate_array("After InvShiftRows", state);
SubBytes(state, S_dec);
accumulate_array("After SubBytes", state);
AddRoundKey(state, w, 0);
accumulate_array("Output", state);
// process output
AES_output = transpose(state);
format_AES_output();
//details_value = accumulated_output_info;
}
参考:基于JavaScript的AES算法加密解密实现(源码)
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net