aardio-SM4库源码:

class SM4{
ctor( key/*输入构造函数所需要的参数*/ ){
this.secrykey=key;
};
/* 密钥拓展 */ //key byte[]
keyGenerate=function( key) {
var key_r = {};//轮密钥rk_i
var key_temp = {};
var box_in, box_out;//盒变换输入输出
var FK = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};
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
};
//将输入的密钥每32比特合并,并异或FK
for(i=1;4;1){
key_temp[i] = this.jointBytes(key[4 * (i-1)+1], key[4 * (i-1)+2], key[4 * (i-1)+3], key[4 * (i-1)+4]);
key_temp[i] = key_temp[i] ^ FK[i];
}
//32轮密钥拓展
for (i=1;32;1) {
box_in = key_temp[2] ^ key_temp[3] ^ key_temp[4] ^ CK[i];
box_out = this.sBox(box_in);
key_r[i] = key_temp[1] ^ box_out ^ this.shift(box_out, 13) ^ this.shift(box_out, 23);
key_temp[1] = key_temp[2];
key_temp[2] = key_temp[3];
key_temp[3] = key_temp[4];
key_temp[4] = key_r[i];
}
return key_r;
};
/* 加解密主模块 */
sm4Main=function ( input, key_r, mod) {
var text = {};//32比特字
//将输入以32比特分组
for (i=1;4;1) {
text[i] = this.jointBytes(input[4 * (i-1)+1], input[4 * (i-1)+1 + 1], input[4 * (i-1)+1 + 2], input[4 * (i-1)+1 + 3]);
}
var box_input, box_output;//盒变换输入和输出
for (i=1;32;1) {
var index = (mod == 0) ? i : (33 - i);//通过改变key_r的顺序改变模式
box_input = text[2] ^ text[3] ^ text[4] ^ key_r[index];
box_output = this.sBox(box_input);
var temp = text[1] ^ box_output ^ this.shift(box_output, 2) ^ this.shift(box_output, 10) ^ this.shift(box_output, 18) ^ this.shift(box_output, 24);
text[1] = text[2];
text[2] = text[3];
text[3] = text[4];
text[4] = temp;
}
var output ={};//输出
//将结果的32比特字拆分
for (i=4;1;-1) {
..table.append(output,this.splitInt(text[i]))
}
return output;
};
/* 加密 */
encrypt=function( plaintext) {
this.key_r=this.keyGenerate(this.secrykey);
return this.sm4Main(plaintext, this.key_r, 0);
};
encryptBase64=function(plaintext){
import crypt
var cc=this.encrypt(plaintext)
var s=""
for(i=1;#cc;1){
s=s++..string.pack(cc[i])
}
return crypt.encodeBin(s)
};
/* 解密 */
decrypt=function( ciphertext) {
this.key_r=this.keyGenerate(this.secrykey);
return this.sm4Main(ciphertext, this.key_r, 1);
};
decryptStr=function(ciphertext){
import crypt
var cc=this.decrypt(crypt.decodeBin(ciphertext))
var s=""
for(i=1;#cc;1){
s=s++..string.pack(cc[i])
}
return s
}

/* 将32比特数拆分成4个8比特数 */
splitInt=function( n) {
return {(n >> 24) & 0xFF, (n >> 16)& 0xFF, (n >> 8)& 0xFF, n};
};
/* 将4个8比特数合并成32比特数 */
jointBytes=function( byte_0, byte_1, byte_2, byte_3) {
var s= ..string.format("%02x", byte_0 & 0xFF)++
..string.format("%02x",byte_1 & 0xFF)++
..string.format("%02x",byte_2 & 0xFF)++
..string.format("%02x",byte_3 & 0xFF);
return tonumber(s,16);
};

/* S盒变换 */
sBox=function( box_input) {
//s盒的参数
var SBOX = {
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 temp = this.splitInt(box_input);//拆分32比特数
var output = {};//单个盒变换输出
//盒变换
for (i=1;4;1) {
output[i] = SBOX[(temp[i] & 0xFF)+1];
}
//将4个8位字节合并为一个字作为盒变换输出
return this.jointBytes(output[1], output[2], output[3], output[4]);
};
/* 将input左移n位 */
shift=function( input, n) {
return (input >>> (32 - n)) | (input << n);
};
}

网友分享的另一个SM4库,性能要低些,仅供参考。

//SM4 加密解密库 SM4.aardio

class SM4{
ctor( key ){
this.rk = r_key(key);
};
encrypt = function(inputData){
return encrypt (inputData,this.rk);
}
decrypt = function (inputData){
return decrypt (inputData,this.rk);
}
}

namespace SM4 {
// Expanded SM4 box table
SM4_BOXES = {
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
};

// System parameter
SM4_FK = {0xa3b1bac6; 0x56aa3350; 0x677d9197; 0xb27022dc};

// fixed parameter
SM4_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
};

//8位查S盒
s_box = function (a) {
// ah = (a & 0xf0) >>> 4; //高4位
//al = a & 0x0f; //低4位
//return SM4_BOXES[ah*16+al+1] ;
return SM4_BOXES[a + 1];
};

//非线性变换T
fun_T = function (ta){
tb = {
s_box((ta & 0xff000000) >>> 24); ///取高8位,进行S盒变换
s_box((ta & 0x00ff0000) >>> 16); ///取中高8位,进行S盒变换
s_box((ta & 0x0000ff00) >>> 8 ); ///取中低8位,进行S盒变换
s_box(ta & 0x000000ff ); ///取低8位,进行S盒变换
}
return tb[1]<<24 | tb[2]<<16 | tb[3]<< 8 | tb[4]; ///连接成32位
}

//循环左移
bit_rol = function (n,s){
return (n << s) | ( n >>> (32 - s));
}

//轮密钥
r_key = function (key){
keyBuf = ..raw.buffer(16,key);
mk = { //拆分密钥为4个32位数存到初始密钥MK
(keyBuf[1]<<24 | keyBuf[2]<<16 | keyBuf[3]<<8 | keyBuf[4]); // &0xFFFFFFFF
(keyBuf[5]<<24 | keyBuf[6]<<16 | keyBuf[7]<<8 | keyBuf[8]);
(keyBuf[9]<<24 | keyBuf[10]<<16 | keyBuf[11]<<8 | keyBuf[12]);
(keyBuf[13]<<24 | keyBuf[14]<<16 | keyBuf[15]<<8 | keyBuf[16]);
}
tk = {}; //临时表tk
for(i=1;4;1){
tk[i] = mk[i] ^ SM4_FK[i]; //初始密钥MK和系统参数FK作异或运算得到tk1-tk4
}
rk = {};
for(i=1;32;1){ ///轮密钥tk5-tk36
tb = fun_T( tk[i+1] ^ tk[i+2] ^ tk[i+3] ^ SM4_CK[i] ); //后3个字与固定参数异或,得到的32位的值,再进行变换
tk[i+4] = tk[i] ^ (tb ^ bit_rol(tb,13) ^ bit_rol(tb,23)); ///得到轮密钥tk5-tk36
rk[i] = tk[i+4]; //子密钥rk1-32
}
return rk;
}

//线性变换L
fun_L = function (tb){
return (tb ^ bit_rol(tb,2) ^ bit_rol(tb,10) ^ bit_rol(tb,18) ^ bit_rol(tb,24));
}

//尾部填充
pkcs7_padding = function(data, block=16){
var n = block - (#data % block )
return data ++ ..string.repeat(n, n));
}

//去除尾部填充
pkcs7_unPadding = function(data){
return ..string.left(data, #data - tonumber(..string.right(data,2),16)*2 );
}

//32次迭代,mode=1加密,mode=0解密
iterate32 = function (rk,d1,d2,d3,d4,mode = 1){
dataTable = {d1,d2,d3,d4};
for(i=1;32;1){
if(mode=1){
a = ((dataTable[i+1] ^ dataTable[i+2] ^ dataTable[i+3]) ^ rk[i]) // &0xFFFFFFFF
}else {
a = ((dataTable[i+1] ^ dataTable[i+2] ^ dataTable[i+3]) ^ rk[33-i])
}
dataTable[i+4] = dataTable[i] ^ fun_L(fun_T(a)) ///先T变换再L变换
}
return ..string.format("%08x",dataTable[36]) ++ ..string.format("%08x",dataTable[35]) ++ ..string.format("%08x",dataTable[34]) ++ ..string.format("%08x",dataTable[33])
}

encrypt = function (inputData,rk){
inputData = pkcs7_padding(inputData,16);
var data = {};
inputDataBuf = ..raw.buffer(inputData);
for(i=0;#inputDataBuf/16 - 1; 1){
var a1 = inputDataBuf[i*16+1]<<24 | inputDataBuf[i*16+2]<<16 | inputDataBuf[i*16+3]<<8 | inputDataBuf[i*16+4]; //& 0x0ffffffff
var a2 = inputDataBuf[i*16+5]<<24 | inputDataBuf[i*16+6]<<16 | inputDataBuf[i*16+7]<<8 | inputDataBuf[i*16+8];
var a3 = inputDataBuf[i*16+9]<<24 | inputDataBuf[i*16+10]<<16 | inputDataBuf[i*16+11]<<8 | inputDataBuf[i*16+12];
var a4 = inputDataBuf[i*16+13]<<24 | inputDataBuf[i*16+14]<<16 | inputDataBuf[i*16+15]<<8 | inputDataBuf[i*16+16];
..table.push(data, iterate32(rk,a1,a2,a3,a4,1));
}
return ..string.join(data);
}

decrypt = function (inputData,rk){
var data = {};
for(i=1;#inputData; 32){
var a1 = tonumber(..string.slice( inputData,i,i+7),16);
var a2 = tonumber(..string.slice( inputData,i+8,i+15),16);
var a3 = tonumber(..string.slice( inputData,i+16,i+23),16);
var a4 = tonumber(..string.slice( inputData,i+24,i+31),16);
..table.push(data, iterate32( rk,a1,a2,a3,a4,0));
}
return pkcs7_unPadding(..string.join(data));
}
}


测试该算法的代码:

import fsys.file
import crypt;
console.open();
key = "abcd123456789012"
inputData = "abcdefghijklmnop123456789012345678"


var sm = sm4(key)
console.dump(sm.encrypt(inputData))
var tm = time.tick()
for(i=1;10000;1){
sm.encrypt(inputData)
}
console.dump("文件内加密耗时:"++time.tick()-tm)
var odata = sm.encrypt(inputData)

import SM4
var sm = SM4(key)
console.dump(sm.encrypt(inputData))
var tm = time.tick()
for(i=1;10000;1){
sm.encrypt(inputData)
}
console.dump("库加密耗时:"++time.tick()-tm)

var sm = sm4(key)
console.dump(sm.decrypt (odata))
var tm = time.tick()
for(i=1;10000;1){
sm.decrypt (odata)
}
console.dump("文件内解密耗时:"++time.tick()-tm)

var sm = SM4(key)
console.dump(sm.decrypt(odata))
var tm = time.tick()
for(i=1;10000;1){
sm.decrypt(odata)
}
console.dump("库解密耗时:"++time.tick()-tm)

var tm = time.tick()
for(i=1;10000;1){
var sm = sm4(key)
sm.encrypt(inputData)
}
console.dump("循环创建对象耗时:"++time.tick()-tm)

var tm = time.tick()
for(i=1;10000;1){
var sm = SM4(key)
sm.encrypt(inputData)
}
console.dump("循环创建对象耗时:"++time.tick()-tm)


console.pause()