简介:全称高级加密标准(英文名称:Advanced Encryption Standard),在密码学中又称 Rijndael 加密法,由美国国家标准与技术研究院 (NIST)于 2001 年发布,并在 2002 年成为有效的标准,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的 DES,已经被多方分析且广为全世界所使用,它本身只有一个密钥,即用来实现加密,也用于解密。- mode 支持:CBC,CFB,CTR,CTRGladman,ECB,OFB 等。 - padding 支持:ZeroPadding,NoPadding,AnsiX923,Iso10126,Iso97971,Pkcs7 等- **CFB模式** 全称Cipher FeedBack模式,译为密文反馈模式- **OFB模式** 全称Output Feedback模式,译为输出反馈模式。- **CTR模式** 全称Counter模式,译为计数器模式。- **iv:** 防止同样的明文块、加密成同样的密文块参数定义:
- key length(密钥位数,密码长度)
AES128,AES192,AES256(128 位、192 位或 256 位)
- key (密钥,密码)key指的就是密码了,
AES128
就是128位
的,如果位数不够,某些库可能会自动填充到128
。- IV (向量)IV称为初始向量,不同的IV加密后的字符串是不同的,加密和解密需要相同的IV。
- mode (加密模式)AES分为几种模式,比如ECB,CBC,CFB等等,这些模式除了ECB由于没有使用IV而不太安全,其他模式差别并没有太明显。
- padding (填充方式)对于加密解密两端需要使用同一的PADDING模式,大部分PADDING模式为
PKCS5, PKCS7, NOPADDING
。加密原理:
AES加密算法采用分组密码体制,每个分组数据的长度为128位16个字节,密钥长度可以是128位16个字节、192位或256位,一共有四种加密模式,我们通常采用需要初始向量IV的CBC模式,初始向量的长度也是128位16个字节。
//des
//this takes the key, the message, and whether to encrypt or decrypt
function des(key, message, encrypt, mode, iv, padding) {//declaring this locally speeds things up a bitvar spfunction1 = new Array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400, 0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000, 0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4, 0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404, 0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400, 0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004);var spfunction2 = new Array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, -0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, -0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, -0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, -0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0, 0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, -0x7fef7fe0, 0x108000);var spfunction3 = new Array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008, 0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000, 0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000, 0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0, 0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208, 0x8020000, 0x20208, 0x8, 0x8020008, 0x20200);var spfunction4 = new Array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000, 0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080, 0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0, 0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001, 0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080);var spfunction5 = new Array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000, 0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000, 0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100, 0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100, 0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100, 0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0, 0x40080000, 0x2080100, 0x40000100);var spfunction6 = new Array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000, 0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010, 0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000, 0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000, 0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000, 0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010);var spfunction7 = new Array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802, 0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002, 0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000, 0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000, 0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0, 0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002);var spfunction8 = new Array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000, 0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000, 0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040, 0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000);//create the 16 or 48 subkeys we will needvar keys = des_createKeys(key);var m = 0, i, j, temp, temp2, right1, right2, left, right, looping;var cbcleft, cbcleft2, cbcright, cbcright2var endloop, loopinc;var len = message.length;var chunk = 0;//set up the loops for single and triple desvar iterations = keys.length == 32 ? 3 : 9; //single or triple desif (iterations == 3) {looping = encrypt ? new Array(0, 32, 2) : new Array(30, -2, -2);}else {looping = encrypt ? new Array(0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array(94, 62, -2, 32, 64, 2, 30, -2, -2);}//pad the message depending on the padding parameterif (padding == 2) message += " "; //pad the message with spaceselse if (padding == 1) {temp = 8 - (len % 8);message += String.fromCharCode(temp, temp, temp, temp, temp, temp, temp, temp);if (temp == 8) len += 8;} //PKCS7 paddingelse if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes//store the result herevar result = "";var tempresult = "";if (mode == 1) { //CBC modecbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);m = 0;}//loop through each 64 bit chunk of the messagewhile (m < len) {left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message.charCodeAt(m++);//for Cipher Block Chaining mode, xor the message with the previous resultif (mode == 1) {if (encrypt) {left ^= cbcleft;right ^= cbcright;} else {cbcleft2 = cbcleft;cbcright2 = cbcright;cbcleft = left;cbcright = right;}}//first each 64 but chunk of the message must be permuted according to IPtemp = ((left >>> 4) ^ right) & 0x0f0f0f0f;right ^= temp;left ^= (temp << 4);temp = ((left >>> 16) ^ right) & 0x0000ffff;right ^= temp;left ^= (temp << 16);temp = ((right >>> 2) ^ left) & 0x33333333;left ^= temp;right ^= (temp << 2);temp = ((right >>> 8) ^ left) & 0x00ff00ff;left ^= temp;right ^= (temp << 8);temp = ((left >>> 1) ^ right) & 0x55555555;right ^= temp;left ^= (temp << 1);left = ((left << 1) | (left >>> 31));right = ((right << 1) | (right >>> 31));//do this either 1 or 3 times for each chunk of the messagefor (j = 0; j < iterations; j += 3) {endloop = looping[j + 1];loopinc = looping[j + 2];//now go through and perform the encryption or decryption for (i = looping[j]; i != endloop; i += loopinc) { //for efficiencyright1 = right ^ keys[i];right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1];//the result is attained by passing these bytes through the S selection functionstemp = left;left = right;right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f]| spfunction6[(right1 >>> 8) & 0x3f] | spfunction8[right1 & 0x3f]| spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) & 0x3f]| spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);}temp = left;left = right;right = temp; //unreverse left and right} //for either 1 or 3 iterations//move then each one bit to the rightleft = ((left >>> 1) | (left << 31));right = ((right >>> 1) | (right << 31));//now perform IP-1, which is IP in the opposite directiontemp = ((left >>> 1) ^ right) & 0x55555555;right ^= temp;left ^= (temp << 1);temp = ((right >>> 8) ^ left) & 0x00ff00ff;left ^= temp;right ^= (temp << 8);temp = ((right >>> 2) ^ left) & 0x33333333;left ^= temp;right ^= (temp << 2);temp = ((left >>> 16) ^ right) & 0x0000ffff;right ^= temp;left ^= (temp << 16);temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;right ^= temp;left ^= (temp << 4);//for Cipher Block Chaining mode, xor the message with the previous resultif (mode == 1) {if (encrypt) {cbcleft = left;cbcright = right;} else {left ^= cbcleft2;right ^= cbcright2;}}tempresult += String.fromCharCode((left >>> 24), ((left >>> 16) & 0xff), ((left >>> 8) & 0xff), (left & 0xff), (right >>> 24), ((right >>> 16) & 0xff), ((right >>> 8) & 0xff), (right & 0xff));chunk += 8;if (chunk == 512) {result += tempresult;tempresult = "";chunk = 0;}} //for every 8 characters, or 64 bits in the message//return the result as an arrayreturn result + tempresult;
} //end of des//des_createKeys
//this takes as input a 64 bit key (even though only 56 bits are used)
//as an array of 2 integers, and returns 16 48 bit keys
function des_createKeys(key) {//declaring this locally speeds things up a bitvar pc2bytes0 = new Array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204, 0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204);var pc2bytes1 = new Array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100, 0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101);var pc2bytes2 = new Array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808);var pc2bytes3 = new Array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000, 0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000);var pc2bytes4 = new Array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000, 0x41000, 0x1010, 0x41010);var pc2bytes5 = new Array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420, 0x2000000, 0x2000400, 0x2000020, 0x2000420);var pc2bytes6 = new Array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002);var pc2bytes7 = new Array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000, 0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800);var pc2bytes8 = new Array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000, 0x2000002, 0x2040002, 0x2000002, 0x2040002);var pc2bytes9 = new Array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408, 0x10000408, 0x400, 0x10000400, 0x408, 0x10000408);var pc2bytes10 = new Array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020, 0x102000, 0x102020, 0x102000, 0x102020);var pc2bytes11 = new Array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000, 0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200);var pc2bytes12 = new Array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010, 0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010);var pc2bytes13 = new Array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105);//how many iterations (1 for des, 3 for triple des)var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys//stores the return keysvar keys = new Array(32 * iterations);//now define the left shifts which need to be donevar shifts = new Array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);//other variablesvar lefttemp, righttemp, m = 0, n = 0, temp, left, right;for (var j = 0; j < iterations; j++) { //either 1 or 3 iterationsleft = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;right ^= temp;left ^= (temp << 4);temp = ((right >>> -16) ^ left) & 0x0000ffff;left ^= temp;right ^= (temp << -16);temp = ((left >>> 2) ^ right) & 0x33333333;right ^= temp;left ^= (temp << 2);temp = ((right >>> -16) ^ left) & 0x0000ffff;left ^= temp;right ^= (temp << -16);temp = ((left >>> 1) ^ right) & 0x55555555;right ^= temp;left ^= (temp << 1);temp = ((right >>> 8) ^ left) & 0x00ff00ff;left ^= temp;right ^= (temp << 8);temp = ((left >>> 1) ^ right) & 0x55555555;right ^= temp;left ^= (temp << 1);//the right side needs to be shifted and to get the last four bits of the left sidetemp = (left << 8) | ((right >>> 20) & 0x000000f0);//left needs to be put upside downleft = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);right = temp;//now go through and perform these shifts on the left and right keysfor (var i = 0; i < shifts.length; i++) {//shift the keys either one or two bits to the leftif (shifts[i]) {left = (left << 2) | (left >>> 26);right = (right << 2) | (right >>> 26);}else {left = (left << 1) | (left >>> 27);right = (right << 1) | (right >>> 27);}left &= -0xf;right &= -0xf;//now apply PC-2, in such a way that E is easier when encrypting or decrypting//this conversion will look like PC-2 except only the last 6 bits of each byte are used//rather than 48 consecutive bits and the order of lines will be according to //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf]| pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(left >>> 16) & 0xf]| pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf]| pc2bytes6[(left >>> 4) & 0xf];righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf]| pc2bytes9[(right >>> 20) & 0xf] | pc2bytes10[(right >>> 16) & 0xf]| pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf]| pc2bytes13[(right >>> 4) & 0xf];temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;keys[n++] = lefttemp ^ temp;keys[n++] = righttemp ^ (temp << 16);}} //for each iterations//return the keys we've createdreturn keys;
} //end of des_createKeysvar encodeHex = (s) => {let r = '';const hexes = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');for (let i = 0; i < s.length; i++) {r += hexes [s.charCodeAt(i) >> 4] + hexes [s.charCodeAt(i) & 0xf];}return r;
}function decodeHex(h) {let r = '';for (let i = (h.substring(0, 2) === '0x') ? 2 : 0; i < h.length; i += 2) {r += String.fromCharCode(parseInt(h.substring(i, i + 2), 16));}return r;
}//
// 参数说明
/
// key 加密密钥
// message 加密/解密内容
// type 类型
// 加密 0
// 解密 1
// mode 加密模式
// ECB:0
// CBC:1
// iv 密钥向量
// undefined
// null
// ''
// padding 加密填充
// NULL: 0
// PKCS7: 1
// SPACES:2
// NONE: 3var key = "ZmserbBoHQtNP+wOcza/LpngG8yJq42KWYj0DSfdikx3VT16IlUAFM97hECvuRX5";
var message = '{"x33":"0","x34":"0","x35":"0","x36":"3","x37":"0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0","x38":"0|0|1|0|1|0|0|0|0|0|1|0|1|0|1|0|0|0|0|0|0|0","x39":"6","x42":"3.2.9","x43":"532ce42c","x44":"1709601827528","x45":"connecterror","x46":"false","x48":"","x49":"{list:[],type:}"}';// des(key, message, type, mode, iv, padding)
var strEnc = encodeHex( des( key, message, 0, 0, undefined, 0 ) );
console.log( strEnc )// des(key, decodeHex(message), type, mode, iv, padding).replace(/\0/g, '')
var strDec = des(key, decodeHex( strEnc ), 1, 0, key, 0).replace(/\0/g, '');
console.log( strDec )
调用示例