AES 简介 以及 C# 和 js 实现【加密知多少系列_3】

〇、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==/// <summary>
/// AES 加密
/// </summary>
/// <param name="aeseninstr">待加密字符串</param>
/// <param name="secretkey">密钥</param>
/// <returns></returns>
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) <0)return null;byte[] toEncryptArray = Encoding.UTF8.GetBytes(aeseninstr);RijndaelManaged rm = new RijndaelManaged{Key = Encoding.UTF8.GetBytes(secretkey),Mode = CipherMode.ECB,Padding = PaddingMode.PKCS7};ICryptoTransform cTransform = rm.CreateEncryptor();byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);return Convert.ToBase64String(resultArray);
}/// <summary>
/// AES 解密
/// </summary>
/// <param name="aesdeinstr">密文</param>
/// <param name="secretkey">密钥</param>
/// <returns></returns>
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) < 0)return null;byte[] toEncryptArray = Convert.FromBase64String(aesdeinstr);RijndaelManaged rm = new RijndaelManaged{Key = Encoding.UTF8.GetBytes(secretkey),Mode = CipherMode.ECB,Padding = PaddingMode.PKCS7};ICryptoTransform cTransform = rm.CreateDecryptor();byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);return Encoding.UTF8.GetString(resultArray);
}


二、js 语言实现

1、通过引用 crypto-js 实现(操作简单,推荐使用)

// 引入 crypto-js
<script src="http://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/crypto-js.js"></script>
// 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() 方法查看效果。

控制台输出:

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 52function 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 69aes_encrypt();alert(outdata_value) // d1 63 4a fa 0c da da d1 14 e0 fc 63 f1 75 02 cfconsole.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 69alert(hexCharCodeToStr(outdata_value)); // 将 UTF-8 编码的 Hex 类型转为 string
}// 将 string 转为 Hex
function stringToHex(str) {var val = ""for (var i = 0; i < str.length; i++) {if (val == "")val = str.charCodeAt(i).toString(16)elseval += " " + str.charCodeAt(i).toString(16)}return val
}
// 将以 UTF-8 编码的字节序列解码为 String
function hexCharCodeToStr(hex) {console.log("hexCharCodeToStr-hex:",hex);// 将每一字节都转换成 % 加 16 进制数字的表示形式// 再通过 decodeURIComponent 方法解码,得到相应的字符串var bytes = hex.split(" ")var encoded = "";for (var i = 0; i < bytes.length; i++) {encoded += '%' + bytes[i].toString(16)}return decodeURIComponent(encoded)
}
// 将 string 转为以 UTF-8 编码的字节序列
function encodeUtf8(text) {const code = encodeURIComponent(text);const bytes = [];for (var i = 0; i < code.length; i++) {const c = code.charAt(i);if (c === '%') {const hex = code.charAt(i + 1) + code.charAt(i + 2);const hexVal = parseInt(hex, 16);bytes.push(hexVal);i += 2;} else bytes.push(c.charCodeAt(0));}return bytes;
}
// 将字符串转为 ASCII 类型,fix 为自定义分隔符
function strtoascii(str, fix = ' ') {if (str.length < 1)return false;var arr = str.split("");var txt = '';arr.forEach(function (v, i) {txt += fix + v.charCodeAt();});console.log("strtoascii-txt:",txt)return txt;
}// accumulate values to put into text area
var accumulated_output_info;
// add a labeled value to the text area
function accumulate_output(str) {accumulated_output_info = accumulated_output_info + str + "\n";
}
// convert a 8-bit value to a string
function cvt_hex8(val) {var vh = (val >>> 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 digitvar val1 = str.charCodeAt(0);// do some error checkingif (val1 >= 48 && val1 <= 57)// have a valid digit 0-9val1 -= 48;else if (val1 >= 65 && val1 <= 70)// have a valid digit A-Fval1 -= 55;else if (val1 >= 97 && val1 <= 102)// have a valid digit A-Fval1 -= 87;else {// not 0-9 or A-F, complainwindow.alert(str.charAt(1) + " is not a valid hex digit");return -1;}// get the second hex digitvar val2 = str.charCodeAt(1);// do some error checkingif (val2 >= 48 && val2 <= 57)// have a valid digit 0-9val2 -= 48;else if (val2 >= 65 && val2 <= 70)// have a valid digit A-Fval2 -= 55;else if (val2 >= 97 && val2 <= 102)// have a valid digit A-Fval2 -= 87;else {// not 0-9 or A-F, complainwindow.alert(str.charAt(2) + " is not a valid hex digit");return -1;}// all is ok, return the valuereturn val1 * 16 + val2;
}
// add a byte to the output
function accumulate_byte(label, val) {accumulated_output_info += label + cvt_hex8(val) + "\n";
}
// add a word to the output
function accumulate_wordarray(label, ary) {var i, j;accumulated_output_info += label + " ";// process the four elements in this wordfor (j = 0; j < 4; j++)accumulated_output_info += " " + cvt_hex8(ary[j]);// mark the end of the wordaccumulated_output_info += "\n";
}
// add an array to the output
function accumulate_array(label, ary) {var i, j;var spacer = "";// build a set of spaces of equal length to the labelwhile (spacer.length < label.length)spacer += " ";// build the tablefor (i = 0; i < 16; i += 4) {// add label/spacesif (i == 0)accumulated_output_info += label + " ";elseaccumulated_output_info += spacer + " ";// process the four elements in this "row"for (j = 0; j < 4; j++)accumulated_output_info += " " + cvt_hex8(ary[i + j]);// mark the end of this rowaccumulated_output_info += "\n";}
}
// S-Box substitution table
var S_enc = new Array(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
// inverse S-Box for decryptions
var S_dec = new Array(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
// convert two-dimensional indicies to one-dim array indices
var I00 = 0;
var I01 = 1;
var I02 = 2;
var I03 = 3;
var I10 = 4;
var I11 = 5;
var I12 = 6;
var I13 = 7;
var I20 = 8;
var I21 = 9;
var I22 = 10;
var I23 = 11;
var I30 = 12;
var I31 = 13;
var I32 = 14;
var I33 = 15;
// conversion function for non-constant subscripts
// assume subscript range 0..3
function I(x, y) { return (x * 4) + y; }
// remove spaces from input
function remove_spaces(instr) {var i;var outstr = "";for (i = 0; i < instr.length; i++)if (instr.charAt(i) != " ")// not a space, include itoutstr += instr.charAt(i);return outstr;
}
// get the message to encrypt/decrypt or the key
// return as a 16-byte array
function get_value(lbl, str, isASCII) {var dbyte = new Array(16);var i;var val;    // one hex digitif (isASCII) {// check length of dataif (str.length > 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 charactersfor (i = 0; i < 16; i++) {dbyte[i] = str.charCodeAt(i);}}else {// less than 16 characters - fill with NULLsfor (i = 0; i < str.length; i++) {dbyte[i] = str.charCodeAt(i);}for (i = str.length; i < 16; i++) {dbyte[i] = 0;}}}else {// have hex data - remove any spaces they used, then convertstr = remove_spaces(str);// check length of dataif (str.length != 32) {window.alert(lbl + " length wrong: Is " + str.length +" hex digits, but must be 128 bits (32 hex digits)");dbyte[0] = -1;return dbyte;}for (i = 0; i < 16; i++) {// isolate and convert this substringdbyte[i] = cvt_byte(str.substr(i * 2, 2));if (dbyte[i] < 0) {// have an errordbyte[0] = -1;return dbyte;}} // for i} // if isASCII// return successful conversionreturn dbyte;
}
//do the AES GF(2**8) multiplication
// do this by the shift-and-"add" approach
function aes_mul(a, b) {var res = 0;while (a > 0) {if ((a & 1) != 0)res = res ^ b;        // "add" to the resulta >>>= 1;            // shift a to get next higher-order bitb <<= 1;            // shift multiplier also}// now reduce it modulo x**8 + x**4 + x**3 + x + 1var hbit = 0x10000;        // bit to test if we need to take actionvar modulus = 0x11b00;    // modulus - XOR by this to change valuewhile (hbit >= 0x100) {if ((res & hbit) != 0)        // if the high-order bit is setres ^= modulus;    // XOR with the modulus// prepare for the next loophbit >>= 1;modulus >>= 1;}return res;
}
// apply the S-box substitution to the key expansion
function SubWord(word_ary) {var i;for (i = 0; i < 16; i++)word_ary[i] = S_enc[word_ary[i]];return word_ary;
}// rotate the bytes in a word
function RotWord(word_ary) {return new Array(word_ary[1], word_ary[2], word_ary[3], word_ary[0]);
}
// calculate the first item Rcon[i] = { x^(i-1), 0, 0, 0 }
// note we only return the first item
function Rcon(exp) {var val = 2;var result = 1;// remember to calculate x^(exp-1)exp--;// process the exponent using normal shift and multiplywhile (exp > 0) {if ((exp & 1) != 0)result = aes_mul(result, val);// square the valueval = aes_mul(val, val);// move to the next bitexp >>= 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 stufffor (i = 0; i < 16; i++) {w[i] = key[i];}accumulate_wordarray("w[0] = ", w.slice(0, 4));accumulate_wordarray("w[1] = ", w.slice(4, 8));accumulate_wordarray("w[2] = ", w.slice(8, 12));accumulate_wordarray("w[3] = ", w.slice(12, 16));// generate rest of key schedule using 32-bit wordsi = 4;while (i < 44)        // blocksize * ( rounds + 1 ){// copy word W[i-1] to tempfor (j = 0; j < 4; j++)temp[j] = w[(i - 1) * 4 + j];if (i % 4 == 0) {// temp = SubWord(RotWord(temp)) ^ Rcon[i/4];temp = RotWord(temp);accumulate_wordarray("RotWord()=", temp);temp = SubWord(temp);accumulate_wordarray("SubWord()=", temp);temp[0] ^= Rcon(i >>> 2);accumulate_wordarray(" ^ Rcon()=", temp);}// word = word ^ tempfor (j = 0; j < 4; j++)w[i * 4 + j] = w[(i - 4) * 4 + j] ^ temp[j];accumulate_wordarray("w[" + i + "] = ", w.slice(i * 4, i * 4 + 4));i++;}return w;
}
// do S-Box substitution
function SubBytes(state, Sbox) {var i;for (i = 0; i < 16; i++)state[i] = Sbox[state[i]];return state;
}
// shift each row as appropriate
function ShiftRows(state) {var t0, t1, t2, t3;// top row (row 0) isn't shifted// next row (row 1) rotated left 1 placet0 = state[I10];t1 = state[I11];t2 = state[I12];t3 = state[I13];state[I10] = t1;state[I11] = t2;state[I12] = t3;state[I13] = t0;// next row (row 2) rotated left 2 placest0 = state[I20];t1 = state[I21];t2 = state[I22];t3 = state[I23];state[I20] = t2;state[I21] = t3;state[I22] = t0;state[I23] = t1;// bottom row (row 3) rotated left 3 placest0 = state[I30];t1 = state[I31];t2 = state[I32];t3 = state[I33];state[I30] = t3;state[I31] = t0;state[I32] = t1;state[I33] = t2;return state;
}
// inverset shift each row as appropriate
function InvShiftRows(state) {var t0, t1, t2, t3;// top row (row 0) isn't shifted// next row (row 1) rotated left 1 placet0 = state[I10];t1 = state[I11];t2 = state[I12];t3 = state[I13];state[I10] = t3;state[I11] = t0;state[I12] = t1;state[I13] = t2;// next row (row 2) rotated left 2 placest0 = state[I20];t1 = state[I21];t2 = state[I22];t3 = state[I23];state[I20] = t2;state[I21] = t3;state[I22] = t0;state[I23] = t1;// bottom row (row 3) rotated left 3 placest0 = state[I30];t1 = state[I31];t2 = state[I32];t3 = state[I33];state[I30] = t1;state[I31] = t2;state[I32] = t3;state[I33] = t0;return state;
}
// process column info
function MixColumns(state) {var col;var c0, c1, c2, c3;for (col = 0; col < 4; col++) {c0 = state[I(0, col)];c1 = state[I(1, col)];c2 = state[I(2, col)];c3 = state[I(3, col)];// do mixing, and put back into arraystate[I(0, col)] = aes_mul(2, c0) ^ aes_mul(3, c1) ^ c2 ^ c3;state[I(1, col)] = c0 ^ aes_mul(2, c1) ^ aes_mul(3, c2) ^ c3;state[I(2, col)] = c0 ^ c1 ^ aes_mul(2, c2) ^ aes_mul(3, c3);state[I(3, col)] = aes_mul(3, c0) ^ c1 ^ c2 ^ aes_mul(2, c3);}return state;
}
// inverse process column info
function InvMixColumns(state) {var col;var c0, c1, c2, c3;for (col = 0; col < 4; col++) {c0 = state[I(0, col)];c1 = state[I(1, col)];c2 = state[I(2, col)];c3 = state[I(3, col)];// do inverse mixing, and put back into arraystate[I(0, col)] = aes_mul(0x0e, c0) ^ aes_mul(0x0b, c1)^ aes_mul(0x0d, c2) ^ aes_mul(0x09, c3);state[I(1, col)] = aes_mul(0x09, c0) ^ aes_mul(0x0e, c1)^ aes_mul(0x0b, c2) ^ aes_mul(0x0d, c3);state[I(2, col)] = aes_mul(0x0d, c0) ^ aes_mul(0x09, c1)^ aes_mul(0x0e, c2) ^ aes_mul(0x0b, c3);state[I(3, col)] = aes_mul(0x0b, c0) ^ aes_mul(0x0d, c1)^ aes_mul(0x09, c2) ^ aes_mul(0x0e, c3);}return state;
}
// insert subkey information
function AddRoundKey(state, w, base) {var col;for (col = 0; col < 4; col++) {state[I(0, col)] ^= w[base + col * 4];state[I(1, col)] ^= w[base + col * 4 + 1];state[I(2, col)] ^= w[base + col * 4 + 2];state[I(3, col)] ^= w[base + col * 4 + 3];}return state;
}
// return a transposed array
function transpose(msg) {var row, col;var state = new Array(16);for (row = 0; row < 4; row++)for (col = 0; col < 4; col++)state[I(row, col)] = msg[I(col, row)];return state;
}
// final AES state
var AES_output = new Array(16);
// format AES output
// -- uses the global array DES_output
function format_AES_output() {var i;var bits;var str = "";// what type of data do we have to work with?if (false)//document.stuff.outtype[0].checked{// convert each set of bits back to ASCIIfor (i = 0; i < 16; i++)str += String.fromCharCode(AES_output[i]);}else {// output hexdecimal data (insert spaces)str = cvt_hex8(AES_output[0]);for (i = 1; i < 16; i++) {str += " " + cvt_hex8(AES_output[i]);}}// copy to textboxoutdata_value = str;
}
// do encrytion
function aes_encrypt() {var w = new Array(44);            // subkey informationvar state = new Array(16);            // working statevar round;accumulated_output_info = "";// get the message from the user// also check if it is ASCII or hexvar msg = get_value("Message", indata_value, false);//document.stuff.intype[0].checked// problems??if (msg[0] < 0) {//details_value = accumulated_output_info;return;}accumulate_array("Input bits", msg);// get the key from the uservar key = get_value("Key", key_value, false);// problems??if (key[0] < 0) {//details_value = accumulated_output_info;return;}accumulate_array("Key bits", key);// expand the keyaccumulate_output("密钥扩展");w = key_expand(key);// initial state = message in columns (transposed from what we input)state = transpose(msg);accumulate_array("Initial state", state);// display the round key - Transpose due to the way it is stored/usedaccumulate_output("轮密码加");accumulate_array("Round Key", transpose(w.slice(0, 16)));state = AddRoundKey(state, w, 0);for (round = 1; round < 10; round++) {accumulate_array("Round " + round, state);accumulate_output("字节代替");state = SubBytes(state, S_enc);accumulate_array("After SubBytes", state);accumulate_output("行移位");state = ShiftRows(state);accumulate_array("After ShiftRows", state);accumulate_output("列混淆");state = MixColumns(state);accumulate_array("After MixColumns", state);// display the round key - Transpose due to the way it is stored/usedaccumulate_array("Round Key", transpose(w.slice(round * 4 * 4, round * 16 + 16)));accumulate_output("轮密码加");// note here the spec uses 32-bit words, we are using bytes, so an extra *4state = AddRoundKey(state, w, round * 4 * 4);}accumulate_output("字节代替");SubBytes(state, S_enc);accumulate_array("After SubBytes", state);accumulate_output("行移位");ShiftRows(state);accumulate_array("After ShiftRows", state);accumulate_output("轮密码加");AddRoundKey(state, w, 10 * 4 * 4);accumulate_array("Output", state);// process outputAES_output = transpose(state);format_AES_output();//details_value = accumulated_output_info;
}
// do decryption
function aes_decrypt() {var w = new Array(44);            // subkey informationvar state = new Array(16);            // working statevar round;accumulated_output_info = "";        //indata_value = utf16ToUtf8(indata_value.replace(" ",""));console.log("aes_decrypt-indata_value:",indata_value);// get the message from the user// also check if it is ASCII or hexvar msg = get_value("Message", indata_value.toString(), false);//document.stuff.intype[0].checked// problems??if (msg[0] < 0) {//details_value = accumulated_output_info;return;}accumulate_array("Input bits", msg);// get the key from the uservar key = get_value("Key", key_value, false);// problems??if (key[0] < 0) {//details_value = accumulated_output_info;return;}accumulate_array("Key bits", key);// expand the keyw = key_expand(key);// initial state = messagestate = transpose(msg);accumulate_array("Initial state", state);// display the round key - Transpose due to the way it is stored/usedaccumulate_array("Round Key", transpose(w.slice(10 * 4 * 4, 10 * 4 * 4 + 16)));state = AddRoundKey(state, w, 10 * 4 * 4);for (round = 9; round >= 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/usedaccumulate_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 *4state = 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 outputAES_output = transpose(state);format_AES_output();//details_value = accumulated_output_info;
}


三、明文长度与密文长度关系回到顶部

n明文长度密文长度
10~1524
216~3144
332~4764
448~6388
564~79108
680~95128
796~111152
.........
n16(n-1) ~ (16n-1)20n+(n/3+1)x4     (/ :除法取整)

参考:基于JavaScript的AES算法加密解密实现(源码)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37319.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Django模型中的Mysql安装

安装mysql驱动 文章目录 安装mysql驱动1.打开PowerShell 安装mysql的驱动2.安装mysqlclient驱动2.1开始安装2.2 pip list 进行验证 出现mysqlclient 以及pymysql即可 3.正式安装mysql3.1打开mysql官网 www.mysql.com3.2点击下载 然后划到最后点击mysql社区下载 3.3 点击适合win…

AI赋能企业协作6-FizEIM的功能探索

本系列文章AI赋能企业协作与第一个系列IM工具对比中反复比较了国内外、商业、开源的IM工具以及IM工具的AI支持&#xff0c;在之前的比较对象中&#xff0c;由于信息偏差&#xff0c;Workplus&#xff08;BeeWorks&#xff09;已不再开源&#xff0c;这里向各位读者致歉&#xf…

java项目之基于ssm的旅游论坛(源码+文档)

项目简介 旅游论坛实现了以下功能&#xff1a; 用户信息管理&#xff1a; 用户信息新增 用户信息修改 景点信息管理&#xff1a; 景点信息添加 景点信息删除 景点信息修改 论坛类型管理 论坛类型添加 论坛类型修改 论坛类型删除 公告类型管理&#xff1a; 公告类型添加 公…

Linux安装Elasticsearch集群-----docker安装es集群

目录 技术背景 1.2 实验目标 二、实验内容 1.1 服务器规划 二、传统方式安装Elasticsearch集群 2.1 安装Java环境&#xff08;10.1.1.6/8&#xff09; 2.3 配置集群节点&#xff08;以10.1.1.6&#xff09; 2.4 启动服务 ES Data节点1&#xff08;10.1.1.8&#xff09;…

【嵌入式】复刻SQFMI开源的Watchy墨水屏电子表——(2)软件部分

书接上文 基于乐鑫 ESP32-PICO-D4 模块的墨水屏智能手表开源项目Watchy 完成了硬件部分&#xff0c;接下来就是软件部分&#xff1a; 一 开发环境配置&#xff08;Arduino ESP32&#xff09; 首先需要进行 Arduino ESP32 开发环境的安装配置&#xff0c;过程参考之前的帖子&a…

关于微信小程序端base64解码问题

由于atob是浏览器端的&#xff0c;对于微信小程序不支持&#xff0c;导致模拟器【开发工具】显示正常&#xff0c;但真机异常解析失败问题&#xff0c;微信小程序原有的api&#xff0c;官方文档中也废弃了 解决方案&#xff1a; 调用&#xff1a; const decodedString ba…

如何通过Odoo 18创建与配置服务器操作

如何通过Odoo 18创建与配置服务器操作 服务器操作是Odoo实现业务流程自动化的核心工具&#xff0c;允许你在服务器端执行自动化任务&#xff0c;通常由按钮点击或自动化工作流等事件触发。这些操作使用 Python 编写&#xff0c;能够执行复杂的业务逻辑&#xff0c;从而增强 Od…

Windows主机、虚拟机Ubuntu、开发板,三者之间文件互传

以下内容源于日常学习的整理&#xff0c;欢迎交流。 下图是Windows主机、虚拟机Ubuntu、开发者三者之间文件互传的方式示意图&#xff1a; 注意&#xff0c;下面谈及的所有方式&#xff0c;都要求两者的IP地址处于同一网段&#xff0c;涉及到的软件资源见felm。 一、Windows主…

[设计模式与源码]1_Spring三级缓存中的单例模式

欢迎来到啾啾的博客&#x1f431;&#xff0c;一个致力于构建完善的Java程序员知识体系的博客&#x1f4da;&#xff0c;记录学习的点滴&#xff0c;分享工作的思考、实用的技巧&#xff0c;偶尔分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604…

微服务架构中的API网关:Spring Cloud与Kong/Traefik等方案对比

微服务架构中的API网关&#xff1a;Spring Cloud与Kong/Traefik等方案对比 一、API 网关的概念二、API 网关的主要功能2.1 统一入口与路由转发2.2 安全与权限控制2.3 流量管理与容错2.4 API 管理与聚合2.5 监控与日志2.5 协议转换与适配2.6 控制平面与配置管理 三、API 网关选型…

中兴B860AV3.2-T/B860AV3.1-T2_S905L3-B_2+8G_安卓9.0_先线刷+后卡刷固件-完美修复反复重启瑕疵

中兴电信B860AV3.2-T&#xff0f;B860AV3.1-T2_晶晨S905L3-B芯片_28G_安卓9.0_先线刷后卡刷-刷机固件包&#xff0c;完美修复刷机后盒子反复重启的瑕疵。 这两款盒子是可以通刷的&#xff0c;最早这个固件之前论坛本人以及其他水友都有分享交流过不少的固件&#xff0c;大概都…

Stable Diffusion lora训练(一)

一、不同维度的LoRA训练步数建议 2D风格训练 数据规模&#xff1a;建议20-50张高质量图片&#xff08;分辨率≥10241024&#xff09;&#xff0c;覆盖多角度、多表情的平面风格。步数范围&#xff1a;总步数控制在1000-2000步&#xff0c;公式为 总步数 Repeat Image Epoch …

Web3 时代数据保护的关键挑战与应对策略

Web3 时代数据保护的关键挑战与应对策略 随着互联网技术的飞速发展&#xff0c;我们正步入 Web3 时代&#xff0c;这是一个以去中心化、用户主权和数据隐私为核心的新时代。在这个时代&#xff0c;数据保护成为了一个至关重要的议题。本文将探讨 Web3 时代数据保护面临的主要挑…

微信小程序计算属性与监听器:miniprogram-computed

小程序框架没有提供计算属性相关的 api &#xff0c;但是官方为开发者提供了拓展工具库 miniprogram-computed。 该工具库提供了两个功能&#xff1a; 计算属性 computed监听器 watch 一、安装 miniprogram-computed 在项目的根目录下&#xff0c;使用如下命令&#xff0c;…

实体机安装linux视频教程。windows和ubuntu共存。启动时选择切换引导系统。

登录ubuntu官网下载iso镜像。 https://ubuntu.com/download 桌面版带G U I 操作界面&#xff0c;服务版靠远程命令行操作&#xff0c;类似wsl&#xff0c;没有图形界面&#xff0c;显卡跑满无需分散算力到显示交互界面上。 点alter natice downloads可以下载旧版本。具体版本选…

Numpy

一、Numpy优势 学习目标 目标 了解Numpy运算速度上的优势 知道Numpy的数组内存块风格 知道Numpy的并行化运算 1 Numpy介绍 Numpy&#xff08;Numerical Python&#xff09;是一个开源的Python科学计算库&#xff0c;用于快速处理任意维度的数组。 Numpy支持常见的数组和矩…

小红书不绑定手机号会显示ip吗

小红书作为一个生活方式分享平台&#xff0c;拥有庞大的用户群体。在小红书上&#xff0c;用户可以分享自己的生活点滴、购物心得、美食体验等&#xff0c;与其他用户进行互动交流。最近&#xff0c;不少用户对于小红书是否会在不绑定手机号的情况下显示IP属地产生了疑问&#…

FPGA multiboot 方案

FPGA multiboot 方案 初版方案 初版方案不需要软件参与&#xff0c;只是为了验证flash启动。当前已完成。 使用jtag 通过vivaod harwaremanager去将fpga bit流文件加载到demo板flash中。 具体操作&#xff1a; 约束添加for golden bitstream # 设置电源参考&#xff0c;1.…

SpringBoot的启动原理?

大家好&#xff0c;我是锋哥。今天分享关于【SpringBoot的启动原理&#xff1f;】面试题。希望对大家有帮助&#xff1b; SpringBoot的启动原理&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot的启动原理主要是通过 SpringApplication 类来…

aws训练快速入门教程

AWS 相关核心概念 简洁地介绍一下AWS训练云服务的核心关联概念: AWS核心服务层: 基础设施层: EC2(计算), S3(存储), RDS(数据库)等人工智能层: SageMaker(训练平台), AI服务等 机器学习服务分级: 高层: 预构建AI服务(开箱即用)中层: SageMaker(主要训练平台)底层: 框架和基…