hb_zhgd_screen/js/smutil/sm4.js

341 lines
11 KiB
JavaScript
Raw Permalink Normal View History

2025-10-13 09:33:54 +08:00
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>SM4<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>sm4.js<EFBFBD><EFBFBD>޸ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϰ汾<EFBFBD><EFBFBD>Numberλ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD>ܽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԣ<EFBFBD>
* <EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӽ<EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD>Ϊ<EFBFBD><EFBFBD>BigInteger<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD>Java<EFBFBD><EFBFBD><EFBFBD><EFBFBD>SM4.java<EFBFBD><EFBFBD><EFBFBD>㷽ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* @date 2018-10
*/
function SM4Context() {
this.mode = 1;
this.isPadding = true;
this.sk = new Array(32);
}
function SM4() {
this.SM4_ENCRYPT = 1;
this.SM4_DECRYPT = 0;
this.S_BOX_TABLE = [0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48];
// var FK = [ 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc ];
//<2F>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תBigInteger<65><72><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>Java<76><61>һ<EFBFBD>£<EFBFBD><C2A3><EFBFBD>1<EFBFBD><31>4λתΪ<D7AA>з<EFBFBD><D0B7>ţ<EFBFBD>Java<76><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD>int<6E>з<EFBFBD><D0B7>Ž<EFBFBD><C5BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
this.FK = ['-5c4e453a', '56aa3350', '677d9197', '-4d8fdd24'];
// var CK = [0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
// 0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
// 0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
// 0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
// 0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
// 0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
// 0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
// 0x10171e25,0x2c333a41,0x484f565d,0x646b7279];
this.CK = ['70e15', '1c232a31', '383f464d', '545b6269',
'70777e85', '-736c655f', '-57504943', '-3b342d27',
'-1f18110b', '-3fcf5ef', '181f262d', '343b4249',
'50575e65', '6c737a81', '-77706963', '-5b544d47',
'-3f38312b', '-231c150f', '-700f9f3', '141b2229',
'30373e45', '4c535a61', '686f767d', '-7b746d67',
'-5f58514b', '-433c352f', '-27201913', '-b04fdf7',
'10171e25', '2c333a41', '484f565d', '646b7279'];
this.getUlongBE = function(b, i) {
var b1 = new BigInteger(String(b[i] & 0xff)).shiftLeft(24);
var b2 = new BigInteger(String(b[i + 1] & 0xff)).shiftLeft(16);
var b3 = new BigInteger(String(b[i + 2] & 0xff)).shiftLeft(8);
var b4 = new BigInteger(String(b[i + 3] & 0xff)).and(new BigInteger("FFFFFFFF", 16));
return b1.or(b2).or(b3).or(b4);
//return (b[i] & 0xff) << 24 | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | (b[i + 3] & 0xff) & 0xffffffff;
};
this.putUlongBE = function(n, b, i) {
b[i] = n.shiftRight(24).and(new BigInteger("0xFF", 16)).byteValue();
b[i + 1] = n.shiftRight(16).and(new BigInteger("0xFF", 16)).byteValue();
b[i + 2] = n.shiftRight(8).and(new BigInteger("0xFF", 16)).byteValue();
b[i + 3] = n.and(new BigInteger("0xFF", 16)).byteValue();
// var t1=(0xFF & (n >> 24));
// var t2=(0xFF & (n >> 16));
// var t3=(0xFF & (n >> 8));
// var t4=(0xFF & (n));
// b[i] = t1>128?t1-256:t1;
// b[i + 1] = t2>128?t2-256:t2;
// b[i + 2] = t3>128?t3-256:t3;
// b[i + 3] = t4>128?t4-256:t4;
};
this.rotl = function(x, n) {
//(x & 0xFFFFFFFF) << n;
var b1 = x.and(new BigInteger("FFFFFFFF", 16)).shiftLeft(n);
return b1.or(x.shiftRight(32 - n));
//return this.SHL(x, n) | x >> (32 - n);
};
this.sm4Lt = function(ka) {
var a = new Array(4);
var b = new Array(4);
this.putUlongBE(ka, a, 0);
b[0] = this.sm4Sbox(a[0]);
b[1] = this.sm4Sbox(a[1]);
b[2] = this.sm4Sbox(a[2]);
b[3] = this.sm4Sbox(a[3]);
var bb = this.getUlongBE(b, 0);
var c = bb.xor(this.rotl(bb, 2)).xor(this.rotl(bb, 10)).xor(this.rotl(bb, 18)).xor(this.rotl(bb, 24));
// c = bb ^ this.rotl(bb, 2) ^ this.rotl(bb, 10) ^ this.rotl(bb, 18) ^ this.rotl(bb, 24);
return c;
};
this.sm4F = function(x0, x1, x2, x3, rk) {
return x0.xor(this.sm4Lt(x1.xor(x2).xor(x3).xor(rk)));
// return x0 ^ this.sm4Lt(x1 ^ x2 ^ x3 ^ rk);
};
this.sm4CalciRK = function(ka) {
var a = new Array(4);
var b = new Array(4);
this.putUlongBE(ka, a, 0);
b[0] = this.sm4Sbox(a[0]);
b[1] = this.sm4Sbox(a[1]);
b[2] = this.sm4Sbox(a[2]);
b[3] = this.sm4Sbox(a[3]);
var bb = this.getUlongBE(b, 0);
// rk = bb ^ this.rotl(bb, 13) ^ this.rotl(bb, 23);
var rk = bb.xor(this.rotl(bb, 13)).xor(this.rotl(bb, 23));
return rk;
};
this.sm4Sbox = function(inch) {
var i = inch & 0xFF;
var retVal = this.S_BOX_TABLE[i];
return retVal > 128 ? retVal - 256 : retVal;
};
this.sm4SetKeyEnc = function(ctx, key) {
if (ctx == null) {
alert("ctx is null!");
return false;
}
if (key == null || key.length != 16) {
alert("key error!");
return false;
}
ctx.mode = this.SM4_ENCRYPT;
this.sm4SetKey(ctx.sk, key);
};
this.sm4SetKeyDec = function(ctx, key) {
this.sm4SetKeyEnc(ctx, key);
ctx.mode = this.SM4_DECRYPT;
for (var i = 0; i < 16; i++) {
// this.SWAP(ctx.sk, i);
var t = ctx.sk[i];
ctx.sk[i] = ctx.sk[(31 - i)];
ctx.sk[(31 - i)] = t;
}
};
this.sm4SetKey = function(SK, key) {
var MK = new Array(4);// bint
var k = new Array(36);// bint
MK[0] = this.getUlongBE(key, 0);
MK[1] = this.getUlongBE(key, 4);
MK[2] = this.getUlongBE(key, 8);
MK[3] = this.getUlongBE(key, 12);
k[0] = MK[0].xor(new BigInteger(this.FK[0], 16));//MK[0] ^ FK[0];
k[1] = MK[1].xor(new BigInteger(this.FK[1], 16));//MK[1] ^ FK[1];
k[2] = MK[2].xor(new BigInteger(this.FK[2], 16));//MK[2] ^ FK[2];
k[3] = MK[3].xor(new BigInteger(this.FK[3], 16));//MK[3] ^ FK[3];
for (var i = 0; i < 32; i++) {
k[(i + 4)] = k[i].xor(this.sm4CalciRK(k[i + 1].xor(k[(i + 2)]).xor(k[(i + 3)]).xor(new BigInteger(this.CK[i], 16))));
// k[(i + 4)] = (k[i] ^ this.sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ CK[i]));
SK[i] = k[(i + 4)];
}
};
this.padding = function(input, mode) {
if (input == null) {
return null;
}
var ret = null;
if (mode == this.SM4_ENCRYPT) {
var p = parseInt(16 - input.length % 16);
ret = input.slice(0);
for (var i = 0; i < p; i++) {
ret[input.length + i] = p;
}
} else {
var p = input[input.length - 1];
ret = input.slice(0, input.length - p);
}
return ret;
};
this.sm4OneRound = function(sk, input, output) {
var i = 0;
var ulbuf = new Array(36);
ulbuf[0] = this.getUlongBE(input, 0);
ulbuf[1] = this.getUlongBE(input, 4);
ulbuf[2] = this.getUlongBE(input, 8);
ulbuf[3] = this.getUlongBE(input, 12);
while (i < 32) {
ulbuf[(i + 4)] = this.sm4F(ulbuf[i], ulbuf[(i + 1)],
ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
i++;
}
this.putUlongBE(ulbuf[35], output, 0);
this.putUlongBE(ulbuf[34], output, 4);
this.putUlongBE(ulbuf[33], output, 8);
this.putUlongBE(ulbuf[32], output, 12);
};
this.sm4CryptEcb = function(ctx, input) {
if (input == null) {
alert("input is null!");
}
if ((ctx.isPadding) && (ctx.mode == this.SM4_ENCRYPT)) {
input = this.padding(input, this.SM4_ENCRYPT);
}
var i = 0;
var length = input.length;
var bous = new Array();
for (; length > 0; length -= 16) {
var out = new Array(16);
var ins = input.slice(i * 16, (16 * (i + 1)));
this.sm4OneRound(ctx.sk, ins, out)
bous = bous.concat(out);
i++;
}
var output = bous;
if (ctx.isPadding && ctx.mode == this.SM4_DECRYPT) {
output = this.padding(output, this.SM4_DECRYPT);
}
for (var i = 0; i < output.length; i++) {
if (output[i] < 0) {
output[i] = output[i] + 256;
}
}
return output;
};
this.sm4CryptCbc = function(ctx, iv, input) {
if (iv == null || iv.length != 16) {
alert("iv error!");
}
if (input == null) {
alert("input is null!");
}
if (ctx.isPadding && ctx.mode == this.SM4_ENCRYPT) {
input = this.padding(input, this.SM4_ENCRYPT);
}
var i = 0;
var length = input.length;
var bous = new Array();
if (ctx.mode == this.SM4_ENCRYPT) {
var k = 0;
for (; length > 0; length -= 16) {
var out = new Array(16);
var out1 = new Array(16);
var ins = input.slice(k * 16, (16 * (k + 1)));
for (i = 0; i < 16; i++) {
out[i] = (ins[i] ^ iv[i]);
}
this.sm4OneRound(ctx.sk, out, out1);
iv = out1.slice(0, 16);
bous = bous.concat(out1);
k++;
}
} else {
var temp = [];
var k = 0;
for (; length > 0; length -= 16) {
var out = new Array(16);
var out1 = new Array(16);
var ins = input.slice(k * 16, (16 * (k + 1)));
temp = ins.slice(0, 16);
this.sm4OneRound(ctx.sk, ins, out);
for (i = 0; i < 16; i++) {
out1[i] = (out[i] ^ iv[i]);
}
iv = temp.slice(0, 16);
bous = bous.concat(out1);
k++;
}
}
var output = bous;
if (ctx.isPadding && ctx.mode == this.SM4_DECRYPT) {
output = this.padding(output, this.SM4_DECRYPT);
}
for (var i = 0; i < output.length; i++) {
if (output[i] < 0) {
output[i] = output[i] + 256;
}
}
return output;
};
}
function SM4Util() {
var sm4 = new SM4();
this.sm4Encrypt = function(key, text) {
var ctx = new SM4Context();
var keyBytes = strToUtf8Bytes(key);
sm4.sm4SetKeyEnc(ctx, keyBytes);
var encrypted = sm4.sm4CryptEcb(ctx, strToUtf8Bytes(text));
return bytesToHex(encrypted);
};
this.sm4Decrypt = function(key, cipherText) {
var ctx = new SM4Context();
var keyBytes = strToUtf8Bytes(key);
sm4.sm4SetKeyDec(ctx, keyBytes);
var encrypted = sm4.sm4CryptEcb(ctx, hexToBytes(cipherText));
return bytesToUtf8Str(encrypted);
};
this.sm4EncryptCbc = function(key, iv, text) {
var ctx = new SM4Context();
var keyBytes = strToUtf8Bytes(key);
var ivBytes= strToUtf8Bytes(iv) ;
sm4.sm4SetKeyEnc(ctx, keyBytes);
var encrypted = sm4.sm4CryptCbc(ctx, ivBytes, strToUtf8Bytes(text));
return bytesToHex(encrypted);
};
this.sm4DecryptCbc = function(key, iv, cipherText) {
var ctx = new SM4Context();
var keyBytes = strToUtf8Bytes(key);
var ivBytes= strToUtf8Bytes(iv) ;
sm4.sm4SetKeyDec(ctx, keyBytes);
var encrypted = sm4.sm4CryptCbc(ctx, ivBytes, hexToBytes(cipherText));
return bytesToUtf8Str(encrypted);
};
}