分享自己写的一个SM4加密解密的库,另外请大神看看有没有优化的空间,能让解密速度更快。

luren668 2月前 411

import console;

class sm4{
	ctor( key ){
		
		// 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 & 0x0f0) >>> 4  	//高4位
			al = a & 0x00f 			 	//低4位
			return SM4_BOXES[ah*16+al+1] ;
		};
		
		//非线性变换T
		fun_T = function (ta){
			tb = {}  //临时表b
			tb[1] =  s_box((ta & 0x0ff000000) >>> 24)	///取高8位,进行S盒变换
			tb[2] =  s_box((ta & 0x000ff0000) >>> 16)	///取中高8位,进行S盒变换
			tb[3] =  s_box((ta & 0x00000ff00) >>> 8 )	///取中低8位,进行S盒变换
			tb[4] =  s_box(ta & 0x0000000ff ) 		///取低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
			mk[1] = (keyBuf[1]<<24 | keyBuf[2]<<16 | keyBuf[3]<<8 | keyBuf[4] ) & 0x0ffffffff
			mk[2] = (keyBuf[5]<<24 | keyBuf[6]<<16 | keyBuf[7]<<8 | keyBuf[8] ) & 0x0ffffffff
			mk[3] = (keyBuf[9]<<24 | keyBuf[10]<<16 | keyBuf[11]<<8 | keyBuf[12] ) & 0x0ffffffff
			mk[4] = (keyBuf[13]<<24 | keyBuf[14]<<16 | keyBuf[15]<<8 | keyBuf[16] ) & 0x0ffffffff
			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
				//..console.log(i)
				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;
		}
	this.rk = r_key(key)
};
//构造函数结束
		
	//线性变换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 (d1,d2,d3,d4,mode = 1){
			dataTable = {}
			dataTable[1] = d1
			dataTable[2] = d2
			dataTable[3] = d3
			dataTable[4] = d4
			for(i=1;32;1){
				if(mode=1){
					a = ((dataTable[i+1] ^ dataTable[i+2] ^ dataTable[i+3]) ^ rk[i]) & 0x0ffffffff
				}else {
					a = ((dataTable[i+1] ^ dataTable[i+2] ^ dataTable[i+3]) ^ rk[33-i]) & 0x0ffffffff
				}
				dataTable[i+4] = dataTable[i] ^ this.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){
		inputData = this.pkcs7_padding(inputData,16)
		var data = ""
		//..console.log("加密前:",inputData)
		inputDataBuf = ..raw.buffer(inputData)
		for(i=0;#inputDataBuf/16 - 1; 1){
			a1 = inputDataBuf[i*16+1]<<24 | inputDataBuf[i*16+2]<<16 | inputDataBuf[i*16+3]<<8 | inputDataBuf[i*16+4] & 0x0ffffffff
			a2 = inputDataBuf[i*16+5]<<24 | inputDataBuf[i*16+6]<<16 | inputDataBuf[i*16+7]<<8 | inputDataBuf[i*16+8] & 0x0ffffffff
			a3 = inputDataBuf[i*16+9]<<24 | inputDataBuf[i*16+10]<<16 | inputDataBuf[i*16+11]<<8 | inputDataBuf[i*16+12] & 0x0ffffffff
			a4 = inputDataBuf[i*16+13]<<24 | inputDataBuf[i*16+14]<<16 | inputDataBuf[i*16+15]<<8 | inputDataBuf[i*16+16] & 0x0ffffffff
			data =  data ++ this.iterate32(a1,a2,a3,a4,1)
		}
		//..console.log("加密后:",data)
		return data ; 
	}

	//解密
	decrypt = function (inputData){
		var data = ""
		//..console.log("解密前:",inputData)
		for(i=1;#inputData; 32){
			a1 = tonumber(..string.slice( inputData,i,i+7),16)
			a2 = tonumber(..string.slice( inputData,i+8,i+15),16)
			a3 = tonumber(..string.slice( inputData,i+16,i+23),16)
			a4 = tonumber(..string.slice( inputData,i+24,i+31),16)
			tc = this.iterate32(a1,a2,a3,a4,0)
			data =  data ++ tc
		}
		data = this.pkcs7_unPadding(data)
		//..console.dump("解密后:",data)
		return data ; 
	}
	
}
import fsys.file
import crypt;
console.open();
key = "abcd123456789012"
sm4 = sm4(key)

inputData = "abcdefghijklmnop123456789012345678"
console.log("原明文:",inputData)

enStr = sm4.encrypt(inputData)
console.log("加密后:",enStr)

deStr = sm4.decrypt(enStr)
console.log("解密后:",deStr)
dehexStr = crypt.decodeBin(deStr,#deStr,4)
console.log("解码后:",dehexStr)

console.pause()

分享自己写的一个SM4加密解密的库,另外请大神看看有没有优化的空间,能让解密速度更快。

最新回复 (4)
  • 光庆 2月前
    1 2

    稍微改了下,保存为SM4库,没过多研究算法,不知道对不对。

    速度对比:

    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()


    上传的附件:
  • aika107 2月前
    1 3
    我还在地上爬,你已经在研究怎么让高铁速度达到飞机速度,这就是差距
  • 光庆 2月前
    0 4

    以下是另一个版本的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);
        };
    
    }


  • luren668 2月前
    0 5

    实测速度提升40%-50%,看了光庆的代码,才发现我在那里傻傻的拼接字符串,另外对名字空间和类,我总是有点搞不太懂,所以写出来的有点怪异,构造函数里面放了一堆东西。

返回