javascript实现国密hash(sm3)算法(支持微信小程序),可分多次计算

概述:

本人前端需要实现sm3计算的功能,最好是能做到分多次计算。

本文所写的代码在现有sm3的C++代码,反复测试对比计算过程参数,成功改造成sm3的javascript代码,并成功验证好分多次计算sm3数据

测试平台:

已经在如下环境中测试通过,其他平台(浏览器)应该也不会有问题:

1、nodejs中node.exe运行

本js脚本按照版本ES5编写代码,当然微信小程序也能用。

功能代码:

javascript 复制代码
function strSm3CtxParams() {
	this.total;
	this.state;
	this.buffer;
};

function sm3_init() {
	var sm3CtxParams = new strSm3CtxParams();
	
	sm3CtxParams.total = new Array(2);
	sm3CtxParams.state = new Array(8);
	sm3CtxParams.buffer = new Uint8Array(64);
	
	sm3CtxParams.total[0] = 0;  
	sm3CtxParams.total[1] = 0;  

	sm3CtxParams.state[0] = 0x7380166F;  
	sm3CtxParams.state[1] = 0x4914B2B9;  
	sm3CtxParams.state[2] = 0x172442D7;  
	sm3CtxParams.state[3] = 0xDA8A0600;  
	sm3CtxParams.state[4] = 0xA96F30BC;  
	sm3CtxParams.state[5] = 0x163138AA;  
	sm3CtxParams.state[6] = 0xE38DEE4D;  
	sm3CtxParams.state[7] = 0xB0FB0E4E; 
	
	return sm3CtxParams;
}


function sm3_update(sm3CtxParams, data, datalen) {
	var fill = 0;  
	var left = 0;  
	var ilen = datalen;
	var dataIndex = 0;
	var i = 0;

	if( ilen <= 0) {  
		return;  
	}

	left = sm3CtxParams.total[0] & 0x3F;  
	fill = 64 - left;  

	//sm3CtxParams.total[0] += ilen;  
	sm3CtxParams.total[0] = bn_u32_add(sm3CtxParams.total[0], ilen);
	sm3CtxParams.total[0] &= 0xFFFFFFFF;  

	if( sm3CtxParams.total[0] < ilen) { 
		//sm3CtxParams.total[1]++;  
		sm3CtxParams.total[1] = bn_u32_add(sm3CtxParams.total[1], 1);
	}

	if(left != 0 && ilen >= fill) {  
		//memcpy( (void *) (m_Buffer + left),  
		//	(void *) input, fill );  
		for (i = 0; i < fill; i++) {
			sm3CtxParams.buffer[left + i] = data[i + dataIndex];
		}
		Process(sm3CtxParams, sm3CtxParams.buffer, 0);  
		//input += fill;  
		dataIndex += fill;
		ilen  -= fill;  
		left = 0;  
	}  

	while (ilen >= 64) {  
		Process(sm3CtxParams, data, dataIndex);
		//input += 64;  
		dataIndex += 64;
		ilen  -= 64;  
	}  

	if (ilen > 0)  {  
		//memcpy( (void *) (m_Buffer + left),  
		//	(void *) input, ilen );  
		for (i = 0; i < ilen; i++) {
			sm3CtxParams.buffer[left + i] = data[i + dataIndex];
		}
	}  
}

function sm3_final(sm3CtxParams) {
	var last, padn;  
	var high, low;  
	var sm3_padding =  [  
		0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  
	];
	var output = new Uint8Array(32);
	var msglen = new Uint8Array(8);
	var tmpInt = new Array(2);
	
	high = ( (sm3CtxParams.total[0] & 0xffffffff) >>> 29 )  
		| ( sm3CtxParams.total[1] <<  3 );  
	high &= 0xffffffff;
	low  = ( sm3CtxParams.total[0] <<  3 ); 
	low &= 0xffffffff;	
	
	tmpInt[0] = high;
	tmpInt[1] = low;
	PUT_ULONG_BE( tmpInt, 0, msglen, 0 );  
	PUT_ULONG_BE( tmpInt, 1, msglen, 4 );  
	high = tmpInt[0];
	low = tmpInt[1];

	last = sm3CtxParams.total[0] & 0x3F;  
	padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );  

	sm3_update(sm3CtxParams, sm3_padding, padn );  
	sm3_update(sm3CtxParams, msglen, 8 );  

	PUT_ULONG_BE( sm3CtxParams.state, 0, output,  0 );  
	PUT_ULONG_BE( sm3CtxParams.state, 1, output,  4 );  
	PUT_ULONG_BE( sm3CtxParams.state, 2, output,  8 );  
	PUT_ULONG_BE( sm3CtxParams.state, 3, output, 12 );  
	PUT_ULONG_BE( sm3CtxParams.state, 4, output, 16 );  
	PUT_ULONG_BE( sm3CtxParams.state, 5, output, 20 );  
	PUT_ULONG_BE( sm3CtxParams.state, 6, output, 24 );  
	PUT_ULONG_BE( sm3CtxParams.state, 7, output, 28 );  
	
	return output;
}

function PUT_ULONG_BE(n, nindex, b,i){
	(b)[(i)    ] = ( (n[nindex]) >> 24 ) & 0xff;       
	(b)[(i) + 1] = ( (n[nindex]) >> 16 ) & 0xff;       
	(b)[(i) + 2] = ( (n[nindex]) >>  8 ) & 0xff;       
	(b)[(i) + 3] = ( (n[nindex])       ) & 0xff;       
} 

function GET_ULONG_BE(n, nindex, b,i) {                                                       
	n[nindex] = ( (parseInt(b[(i)    ]) & 0xff) << 24 )        
	| ( (parseInt(b[(i) + 1]) & 0xff) << 16 )        
	| ( (parseInt(b[(i) + 2]) & 0xff) <<  8 )        
	| ( (parseInt(b[(i) + 3]) & 0xff)       );       
}

function SHL(x,n) {
	return (((x) & 0xFFFFFFFF) << (n%32));
}

function ROTL(x,n) {
	return (SHL((x),(n)) | ((x) >>> (32 - ((n)%32))));
}

function P0(x) {
	return ((x) ^  ROTL((x),9) ^ ROTL((x),17));
}

function P1(x) {
	return ((x) ^  ROTL((x),15) ^ ROTL((x),23));
}	

function FF0(x,y,z) {
	return ( (x) ^ (y) ^ (z));
}
	
function FF1(x,y,z) {
	return (((x) & (y)) | ( (x) & (z)) | ( (y) & (z)));
}

function GG0(x,y,z) {
	return ( (x) ^ (y) ^ (z));
}
	
function GG1(x,y,z) {
	return (((x) & (y)) | ( (~(x)) & (z)) );
}

//var testi = 0;
function Process(sm3CtxParams, data, dataindex) {  
	//unsigned long SS1, SS2, TT1, TT2, W[68],W1[64];  
	//unsigned long A, B, C, D, E, F, G, H;  
	//unsigned long T[64];  
	//unsigned long Temp1,Temp2,Temp3,Temp4,Temp5;  
	var SS1, SS2, TT1, TT2;
	var j;  
	var T = new Array(64);
	var W = new Array(68);
	var W1 = new Array(64);
	var A, B, C, D, E, F, G, H; 
	var Temp1,Temp2,Temp3,Temp4,Temp5; 

	for(j = 0; j < 16; j++) {
		T[j] = 0x79CC4519;  
	}
	for(j =16; j < 64; j++) {
		T[j] = 0x7A879D8A;  
	}

	GET_ULONG_BE( W, 0, data,  0 + dataindex);  
	GET_ULONG_BE( W, 1, data,  4 + dataindex);  
	GET_ULONG_BE( W, 2, data,  8 + dataindex);  
	GET_ULONG_BE( W, 3, data, 12 + dataindex);  
	GET_ULONG_BE( W, 4, data, 16 + dataindex);  
	GET_ULONG_BE( W, 5, data, 20 + dataindex);  
	GET_ULONG_BE( W, 6, data, 24 + dataindex);  
	GET_ULONG_BE( W, 7, data, 28 + dataindex);  
	GET_ULONG_BE( W, 8, data, 32 + dataindex);  
	GET_ULONG_BE( W, 9, data, 36 + dataindex);  
	GET_ULONG_BE( W, 10, data, 40 + dataindex);  
	GET_ULONG_BE( W, 11, data, 44 + dataindex);  
	GET_ULONG_BE( W, 12, data, 48 + dataindex);  
	GET_ULONG_BE( W, 13, data, 52 + dataindex);  
	GET_ULONG_BE( W, 14, data, 56 + dataindex);  
	GET_ULONG_BE( W, 15, data, 60 + dataindex);  

	//for (j = 0; j < 16; j++) {
	//	console.log("W%d=%d", j, W[j]);
	//}

	for(j = 16; j < 68; j++) {  
		//Below is okay. Interesting, Perhaps VC6 has a bug of Optimizaiton.  
		Temp1 = W[j-16] ^ W[j-9];  
		Temp2 = ROTL(W[j-3],15);  
		Temp3 = Temp1 ^ Temp2;  
		Temp4 = P1(Temp3);  
		Temp5 =  ROTL(W[j - 13],7 ) ^ W[j-6];  
		W[j] = Temp4 ^ Temp5;  
		//console.log("W16=%d", W[16]);
		//aaa;
	}  
	
	//console.log("W17=%d", W[17]);
	//lll;
	//for (j = 0; j < 68; j++) {
	//	console.log("W%d=%d", j, W[j]);
	//}
	//bb;
	//testi++;
	//console.log("testi = %d", testi);
	//if (testi > 1) {
		//throw Error("998");
	//}
	
	for(j =  0; j < 64; j++) {  
		W1[j] = W[j] ^ W[j+4];  
	}  

	A = sm3CtxParams.state[0];  
	B = sm3CtxParams.state[1];  
	C = sm3CtxParams.state[2];  
	D = sm3CtxParams.state[3];  
	E = sm3CtxParams.state[4];  
	F = sm3CtxParams.state[5];  
	G = sm3CtxParams.state[6];  
	H = sm3CtxParams.state[7];  


	for(j =0; j < 16; j++) {  
		//SS1 = ROTL((ROTL(A,12) + E + ROTL(T[j],j)), 7);
		SS1 = bn_u32_add(ROTL(A,12), E);
		SS1 = bn_u32_add(SS1, ROTL(T[j],j));
		SS1 = ROTL(SS1, 7);
		
		//console.log("SS1 = %d", SS1);
		//eee;
		
		SS2 = SS1 ^ ROTL(A,12);  
		//console.log("SS2 = %d", SS2);
		//TT1 = FF0(A,B,C) + D + SS2 + W1[j];  
		TT1 = bn_u32_add(FF0(A,B,C), D);
		TT1 = bn_u32_add(TT1, SS2);
		TT1 = bn_u32_add(TT1, W1[j]);
		//console.log("TT1 = %d", TT1);
		
		//TT2 = GG0(E,F,G) + H + SS1 + W[j];  
		TT2 = bn_u32_add(GG0(E,F,G), H);
		TT2 = bn_u32_add(TT2, SS1);
		TT2 = bn_u32_add(TT2, W[j]);
		//console.log("TT2 = %d", TT2);
		//throw Error("888");
		
		D = C;  
		C = ROTL(B,9);  
		B = A;  
		A = TT1;  
		H = G;  
		G = ROTL(F,19);  
		F = E;  
		E = P0(TT2);  
		
		//console.log("A = %d B = %d C = %d D = %d E = %d F = %d G = %d H = %d", A, B, C, D, E, F, G, H);
		//throw Error("231");
	}  
	//throw Error("996");

	for(j =16; j < 64; j++) {  
		//SS1 = ROTL((ROTL(A,12) + E + ROTL(T[j],j)), 7);   
		SS1 = bn_u32_add(ROTL(A,12), E);
		SS1 = bn_u32_add(SS1, ROTL(T[j],j));
		SS1 = ROTL(SS1, 7);
		
		SS2 = SS1 ^ ROTL(A,12);  
		//TT1 = FF1(A,B,C) + D + SS2 + W1[j];  
		TT1 = bn_u32_add(FF1(A,B,C), D);
		TT1 = bn_u32_add(TT1, SS2);
		TT1 = bn_u32_add(TT1, W1[j]);
		
		//TT2 = GG1(E,F,G) + H + SS1 + W[j];  
		TT2 = bn_u32_add(GG1(E,F,G), H);
		TT2 = bn_u32_add(TT2, SS1);
		TT2 = bn_u32_add(TT2, W[j]);
		
		D = C;  
		C = ROTL(B,9);  
		B = A;  
		A = TT1;  
		H = G;  
		G = ROTL(F,19);  
		F = E;  
		E = P0(TT2); 
		//console.log("A = %d B = %d C = %d D = %d E = %d F = %d G = %d H = %d", A, B, C, D, E, F, G, H);
	} 
	//throw Error("99131");	

	sm3CtxParams.state[0] ^= A;  
	sm3CtxParams.state[1] ^= B;  
	sm3CtxParams.state[2] ^= C;  
	sm3CtxParams.state[3] ^= D;  
	sm3CtxParams.state[4] ^= E;  
	sm3CtxParams.state[5] ^= F;  
	sm3CtxParams.state[6] ^= G;  
	sm3CtxParams.state[7] ^= H;  
 
}  


function bn_u32_add(add1, add2) {
	var i = 0;
	var tmp = 0;
	var result = 0;
	
	add1 &= 0xffffffff;
	add2 &= 0xffffffff;
	
	for (i = 0; i < 4; i++) {
		tmp = ((add1 >>> (i * 8)) & 0xff) + ((add2 >>> (i * 8)) & 0xff) + tmp;
		result |= ((tmp & 0xff) << (i * 8));
		tmp = tmp >>> 8;
	}
	
	return result & 0xffffffff;
}

function bn_u32_minus(minuend, subtractor) {
	var a = (minuend & 0xffffffff) >>> 0;
	var b = (subtractor & 0xffffffff) >>> 0;
	
	return (a - b) & 0xffffffff;
}

function sm3_str_to_array(strIn) {
	var bytesArray = new Uint8Array(strIn.length);
	var i = 0;
	
	for (i = 0; i < strIn.length; i++) {
		bytesArray[i] = strIn.charCodeAt(i);
	}
	
	return bytesArray;
}


function sm3_hex_to_array(hexStrIn) {
  var i = 0;
  var cnt = 0;
  var ele = 0;
  var bytesArray = null;

  cnt = 0;
  for (i = 0; i < hexStrIn.length; i++) {
    ele = hexStrIn.charCodeAt(i);
    if (ele >= 48 && ele < 48 + 10) {
      cnt++;
    }
    if (ele >= 65 && ele < 65 + 6) {
      cnt++;
    }
    if (ele >= 97 && ele < 97 + 6) {
      cnt++;
    }
  }
  bytesArray = new Uint8Array(parseInt((cnt + 1) / 2));
  cnt = 0;
  for (i = 0; i < hexStrIn.length; i++) {
    ele = hexStrIn.charCodeAt(i);
    if (ele >= 48 && ele < 48 + 10) {
      ele -= 48;
      cnt++;
    } else if (ele >= 65 && ele < 65 + 6) {
      ele = ele - 65 + 10;
      cnt++;
    } else if (ele >= 97 && ele < 97 + 6) {
      ele = ele - 97 + 10;
      cnt++;
    } else {
      continue;
    }
    if ((cnt % 2) == 1) {
      bytesArray[parseInt((cnt - 1) / 2)] = (ele << 4) & 0xF0;
    } else {
      bytesArray[parseInt((cnt - 1) / 2)] |= ele;
    }
  }

  return bytesArray;
}

function sm3_encode_hex(result, len) {
	var hex_digits = "0123456789abcdef";
	var output = new String();
	var i = 0;

	for (i = 0; i < len; i++) {
		output += hex_digits.charAt((result[i] >>> 4) & 0x0f);
		output += hex_digits.charAt((result[i]) & 0x0f);
	}
	
	return output;
}

测试代码:

javascript 复制代码
var data1 = "Decrypt";
var data0 = "1234567890abcdef9999oplk8563plmh6003EBFF27AEDE040312E8D8159A91AE0149CDC9EE6775DE602739DB660D241935E8AA847EA015309664C1EBA947E0F043B8CD71240DE448F1D0B758A21E80009BA39A2799515469338E75B810C7550D2B0144DFDCEE981E3250B70F094A2AC98183DFF1B889B8249006ADAEA39504F5F4E8D3581E606D97029880DF721764FF94CD8E66BC1C924DE4451921BB95AF20DA4A9510FDDCCAF0AF88C520D5F6C942446D39079B072429FCA222250F88B753BEA4061E02364528BFEC8F66F4F67CA82CA33DEA0EDFE8FD6E4BF9226B87DB28C0DA0A776CFBD2E4977C0F1E738A443D9D4BE434B9A9F1D9B24D2ACBD7510928A8D4767E8EA8DEC66FF6587237956309";
var data2 = "96325";
//char buf[128];

//EZERO_ARRAY(buf);
var sm3ctx = null;
var result = null;

/* 字符串 */
sm3ctx = sm3_init();
sm3_update(sm3ctx, sm3_str_to_array(data0), data0.length);
sm3_update(sm3ctx, sm3_str_to_array(data1), data1.length);
sm3_update(sm3ctx, sm3_str_to_array(data2), data2.length);
result = sm3_final(sm3ctx);
console.log("result:" + sm3_encode_hex(result, 32));

/* hex */

sm3ctx = sm3_init();
sm3_update(sm3ctx, sm3_hex_to_array("001122334455"), 6);
sm3_update(sm3ctx, sm3_hex_to_array("AABBCCDDEEFF"), 6);
sm3_update(sm3ctx, sm3_hex_to_array("88"), 1);
result = sm3_final(sm3ctx);
console.log("result:" + sm3_encode_hex(result, 32));

测试结果:

经过其他平台工具验证,结果是对的

相关推荐
初遇你时动了情23 分钟前
uniapp 城市选择插件
开发语言·javascript·uni-app
zongzi_4941 小时前
二次封装的天气时间日历选择组件
开发语言·javascript·ecmascript
麻辣_水煮鱼2 小时前
vue数据变化但页面不变
前端·javascript·vue.js
一条晒干的咸魚2 小时前
【Web前端】实现基于 Promise 的 API:alarm API
开发语言·前端·javascript·api·promise
WilliamLuo2 小时前
MP4结构初识-第一篇
前端·javascript·音视频开发
过期的H2O23 小时前
【H2O2|全栈】JS进阶知识(七)ES6(3)
开发语言·javascript·es6
前端Hardy3 小时前
HTML&CSS:数据卡片可以这样设计
前端·javascript·css·3d·html
松树戈3 小时前
JS推荐实践
开发语言·javascript·ecmascript
vener_3 小时前
LuckySheet协同编辑后端示例(Django+Channel,Websocket通信)
javascript·后端·python·websocket·django·luckysheet
老码沉思录3 小时前
React Native 全栈开发实战班 - 性能与调试之打包与发布
javascript·react native·react.js