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

aes,简介,以及,c#,js,实现,加密,知多少,系列 · 浏览次数 : 445

小编点评

**AES算法加密解密实现** ```javascript //获取用户输入的信息 var msg = get_value("Message", indata_value.toString(), false); //获取用户输入的信息 var key = get_value("Key", key_value, false); //获取用户输入的信息 var w = key_expand(key); //初始化工作状态 var state = transpose(msg); //设置明文长度 var n = 16; //设置密文长度 var m = 3144332; //设置明文长度与密文长度的关系式 var r = 10~1524216~3144332~4764448~6388564~79108680~95128796~111152; //加密明文 AES_output = transpose(state); format_AES_output(); //输出加密后的明文 console.log("加密后的明文:", AES_output); ``` **代码说明** 1. 获取用户输入的信息 2. 获取用户输入的信息 3. 获取用户输入的信息 4. 获取用户输入的信息 5. 计算明文长度 6. 计算密文长度 7. 设置明文长度与密文长度的关系式 8. 加密明文 9. 初始化工作状态 10. 设置明文长度 11. 设置密文长度 12. 设置明文长度与密文长度的关系式 13. 加密明文 14. 输出加密后的明文

正文

〇、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() 方法查看效果。

控制台输出:

点击查看 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 < str.length; i++) {
        if (val == "")
            val = str.charCodeAt(i).toString(16)
        else
            val += " " + 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 digit
    var val1 = str.charCodeAt(0);
    // do some error checking
    if (val1 >= 48 && val1 <= 57)
        // have a valid digit 0-9
        val1 -= 48;
    else if (val1 >= 65 && val1 <= 70)
        // have a valid digit A-F
        val1 -= 55;
    else if (val1 >= 97 && val1 <= 102)
        // have a valid digit A-F
        val1 -= 87;
    else {
        // not 0-9 or A-F, complain
        window.alert(str.charAt(1) + " is not a valid hex digit");
        return -1;
    }
    // get the second hex digit
    var val2 = str.charCodeAt(1);
    // do some error checking
    if (val2 >= 48 && val2 <= 57)
        // have a valid digit 0-9
        val2 -= 48;
    else if (val2 >= 65 && val2 <= 70)
        // have a valid digit A-F
        val2 -= 55;
    else if (val2 >= 97 && val2 <= 102)
        // have a valid digit A-F
        val2 -= 87;
    else {
        // not 0-9 or A-F, complain
        window.alert(str.charAt(2) + " is not a valid hex digit");
        return -1;
    }
    // all is ok, return the value
    return 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 word
    for (j = 0; j < 4; j++)
        accumulated_output_info += " " + cvt_hex8(ary[j]);
    // mark the end of the word
    accumulated_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 label
    while (spacer.length < label.length)
        spacer += " ";
    // build the table
    for (i = 0; i < 16; i += 4) {
        // add label/spaces
        if (i == 0)
            accumulated_output_info += label + " ";
        else
            accumulated_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 row
        accumulated_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 it
            outstr += 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 digit
    if (isASCII) {
        // check length of data
        if (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 characters
            for (i = 0; i < 16; i++) {
                dbyte[i] = str.charCodeAt(i);
            }
        }
        else {
            // less than 16 characters - fill with NULLs
            for (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 convert
        str = remove_spaces(str);
        // check length of data
        if (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 substring
            dbyte[i] = cvt_byte(str.substr(i * 2, 2));
            if (dbyte[i] < 0) {
                // have an error
                dbyte[0] = -1;
                return dbyte;
            }
        } // for i
    } // if isASCII
    // return successful conversion
    return 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 result
        a >>>= 1;            // shift a to get next higher-order bit
        b <<= 1;            // shift multiplier also
    }
    // now reduce it modulo x**8 + x**4 + x**3 + x + 1
    var hbit = 0x10000;        // bit to test if we need to take action
    var modulus = 0x11b00;    // modulus - XOR by this to change value
    while (hbit >= 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 < 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 multiply
    while (exp > 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 < 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 words
    i = 4;
    while (i < 44)        // blocksize * ( rounds + 1 )
    {
        // copy word W[i-1] to temp
        for (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 ^ temp
        for (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 place
    t0 = 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 places
    t0 = 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 places
    t0 = 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 place
    t0 = 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 places
    t0 = 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 places
    t0 = 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 array
        state[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 array
        state[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 ASCII
        for (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 textbox
    outdata_value = str;
}
// do encrytion
function aes_encrypt() {
    var w = new Array(44);            // subkey information
    var state = new Array(16);            // working state
    var round;
    accumulated_output_info = "";
    // get the message from the user
    // also check if it is ASCII or hex
    var 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 user
    var 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 key
    accumulate_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/used
    accumulate_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/used
        accumulate_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 *4
        state = 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 output
    AES_output = transpose(state);
    format_AES_output();
    //details_value = accumulated_output_info;
}
// do decryption
function aes_decrypt() {
    var w = new Array(44);            // subkey information
    var state = new Array(16);            // working state
    var 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 hex
    var 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 user
    var 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 key
    w = key_expand(key);
    // initial state = message
    state = transpose(msg);
    accumulate_array("Initial state", state);
    // display the round key - Transpose due to the way it is stored/used
    accumulate_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/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;
}

三、明文长度与密文长度关系

n 明文长度 密文长度
1 0~15 24
2 16~31 44
3 32~47 64
4 48~63 88
5 64~79 108
6 80~95 128
7 96~111 152
... ... ...
n 16(n-1) ~ (16n-1) 20n+(n/3+1)x4     (/ :除法取整)

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

与AES 简介 以及 C# 和 js 实现【加密知多少系列_3】相似的内容:

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

本文首先简单介绍了 AES 的特点,然后再通过两种不同语言的实现进行了实践,提供的实现代码均已经过验证。

前端如何对cookie加密

在前端对 Cookie 进行加密时,你可以使用加密算法对 Cookie 的值进行加密,然后再将加密后的值存储到 Cookie 中。常用的加密算法包括对称加密算法(如 AES)和非对称加密算法(如 RSA)。以下是一个简单的示例,演示如何在前端使用 AES 对 Cookie 进行加密: // 引入加密

C#.NET与JAVA互通之AES加密解密V2024

C#.NET与JAVA互通之AES加密解密V2024 视频: 注意点: 1. KEY 和 IV 从字符串转byte数组时,双方要约定好编码,一般是UTF8。 2.明文从字符串转byte数组时,双方要约定好编码,一般是UTF8,也可以GB2312,但不能Encoding.Default。 3.加密后的

[转帖]JS常见加密 AES、DES、RSA、MD5、SHAI、HMAC、Base64 - Python/JS实现

https://bbs.huaweicloud.com/blogs/386139 【摘要】 本文仅仅介绍了常见的一些JS加密,并记录了JS和Python的实现方式 常见的加密算法基本分为这几类: (1)base64编码伪加密 (2)线性散列算法(签名算法)MD5 (3)安全哈希算法 SHAI (4)

[转帖]Web技术(三):TLS 1.2/1.3 加密原理(AES-GCM + ECDHE-ECDSA/RSA)

文章目录 前言一、TLS 加密原理1.1 TLS 信息加密1.2 TLS 完整性校验与认证加密1.3 TLS 报文结构1.4 TLS 密钥交换1.5 TLS 数字签名1.6 TLS 密码套件1.7 TLS 网络攻防 更多文章: 前言 前篇博客:图解HTTP中谈到,HTTP/1.1 协议默认是以明文方

编码与加密(对称加密与非对称加密)

目录编码与加密Base64编码(可逆)十六进制编码(hex.EncodeToString函数)(可逆)哈希算法(不可逆)MD5(不可逆)SHA-256(不可逆)MAC算法(不可逆)加密算法(可逆)对称加密算法(可逆)DES(可逆)AES(可逆)区别非对称加密算法(可逆)RSA(可逆)ECC(可逆)P

深入理解高级加密标准(Advanced Encryption Standard)

title: 深入理解高级加密标准(Advanced Encryption Standard) date: 2024/4/23 20:04:36 updated: 2024/4/23 20:04:36 tags: AES概述 加密原理 优势特点 算法详解 安全性 应用实践 案例分析 第一章:AES概

[转帖]JCE无限制权限策略文件

https://www.cnblogs.com/rinack/p/13648157.html 因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。比如默认不允许256位密钥的AES加解密,解决方法就是修改策略文件。 对于Java 8 Update 144和更早版本,需要安装J

[转帖]常见加密算法比较

加密算法 常见的 对称加密 算法主要有 DES(数据加密标准)、3DES(三重DES)、AES(高级加密标准) 和Blowfish(河豚鱼)等,常见的 非对称算法 主要有 RSA、DSA 等,散列算法 主要有 SHA-1、SHA-256、MD5 等。 HASH算法(散列算法) 目前常用的是SHA-2

开源.NetCore通用工具库Xmtool使用连载 - 加密解密篇

【Github源码】 《上一篇》详细介绍了Xmtool工具库中的正则表达式类库,今天我们继续为大家介绍其中的加密解密类库。 在开发过程中我们经常会遇到需要对数据进行加密和解密的需求,例如密码的加密、接口传输数据的加密等;当前类库中只封装了Base64、AES两种加密解密方法,因为C#提供了几乎我们能