js的国密sm3加密sm4加解密base64加解密javascript

<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8" />
	<title></title>
	<script src="js/jquery-3.3.1.min.js"></script>
	<script src="js/hex.js"></script>
	<script src="js/sm3.js"></script>
	<script src="js/sm4.js"></script>
	<script src="js/base64.js"></script>
</head>

<body>
	<div style="text-align:center;">
		<form action="#" method="post">

			<table style="margin-left: auto;margin-right: auto;">
				<tr>
					<td style="width:auto;text-align: right;">
						输入消息体:
					</td>
					<td style="text-align: left;" valign="middle">
						<textarea rows="5" cols="50" name="inputtext" id="inputtext"></textarea>
					</td>
				</tr>
				<tr>
					<td style="width:auto;text-align: right;">
						输入key:
					</td>
					<td style="text-align: left;" valign="middle">
						<textarea rows="5" cols="50" name="keytext" id="keytext"></textarea>
					</td>
				</tr>
				<tr>
					<td style="width:auto;text-align: right;">
						加密结果:
					</td>
					<td style="text-align: left;" valign="middle">
						<textarea rows="5" cols="50" name="crypttext" id="crypttext"></textarea>
					</td>
				</tr>

				<tr>
					<td style="width:auto;text-align: right;">
						解密结果:
					</td>
					<td style="text-align: left;" valign="middle">
						<textarea rows="5" cols="50" name="crypttext" id="jiemitext"></textarea>
					</td>
				</tr>

				<tr>
					<td colspan="2" style="width:auto;text-align: center;">
						<input type="button" value="点击生成" id="btn_enc" />
					</td>
				</tr>
			</table>
		</form>
	</div>

	<script>
		var result;
		var jiemiresult;
		var length;
		$("#btn_enc").click(function () {
			let inputtext = $("#inputtext").val();
			let keytext = $("#keytext").val();
			jiami(inputtext, keytext);
			jiemi(result, keytext);
			$("#crypttext").val(result);
			$("#jiemitext").val(jiemiresult);

		});


		function jiami(inputtext, keytext) {
			/*
			 * sm3加密
			 */
			let sm3Data = sm3_encrypt(inputtext)
			console.log(sm3Data);
			let sm3Arr = []
			for (let i = 0; i < sm3Data.length; i++) {
				let aa = sm3Data.slice(i, i + 2)
				aa = hex2int(aa)
				sm3Arr.push(aa)
				i++
			}
			length = sm3Arr.length
			console.log("sm3 jiami:" + sm3Arr);

			// /*
			//  * sm4加密
			//  */
			let input_arr = Hex.utf8StrToBytes(inputtext)
			let data = sm3Arr.concat(input_arr);
			console.log("sm3加密+content:" + data);
			var re = data.length % 16;
			if (re > 0) {
				for (var i = 0; i < 16 - re; i++) {
					data.push(0x00);
				}
			}
			let hex_key = Hex.utf8StrToBytes(keytext)
			var s = sm4_encrypt(data, hex_key);
			console.log("sm4加密:" + s);
			// /*
			//  * base64加密
			//  */
			let u8s = new Uint8Array(s)
			result = Base64.fromUint8Array(u8s);
			console.log("base64加密:" + result);
		};

		function jiemi(result, keytext) {
			// /*
			//  * base64解密
			//  */
			let zz = Base64.toUint8Array(result)
			console.log("base64解密:" + zz);
			// /*
			//  * sm4解密
			//  */
			let hex_key = Hex.utf8StrToBytes(keytext)
			let aa = sm4_decrypt(zz, hex_key)
			for (let i = aa.length - 1; i > aa.length - 16; i--) {
				if (aa[i] == 0) aa.splice(i, 1)
			}
			console.log("sm4解密:" + aa);
			// /*
			//  * 消息体
			//  */
			let content = aa.splice(length, aa.length - 1)
			jiemiresult = Hex.bytesToUtf8Str(content)
			console.log("消息体:" + content);
		}
	</script>
</body>
</html>

**base64.js**
(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ?
		module.exports = factory() :
		typeof define === 'function' && define.amd ?
		define(factory) :
		(function () {
			const _Base64 = global.Base64;
			const gBase64 = factory();
			gBase64.noConflict = () => {
				global.Base64 = _Base64;
				return gBase64;
			};
			if (global.Meteor) { // Meteor.js
				Base64 = gBase64;
			}
			global.Base64 = gBase64;
		})();
}((typeof self !== 'undefined' ? self :
	typeof window !== 'undefined' ? window :
	typeof global !== 'undefined' ? global :
	this
), function () {
	'use strict';
	const version = '3.6.0';
	const VERSION = version;
	const _hasatob = typeof atob === 'function';
	const _hasbtoa = typeof btoa === 'function';
	const _hasBuffer = typeof Buffer === 'function';
	const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;
	const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;
	const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
	const b64chs = [...b64ch];
	const b64tab = ((a) => {
		let tab = {};
		a.forEach((c, i) => tab[c] = i);
		return tab;
	})(b64chs);
	const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
	const _fromCC = String.fromCharCode.bind(String);
	const _U8Afrom = typeof Uint8Array.from === 'function' ?
		Uint8Array.from.bind(Uint8Array) :
		(it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
	const _mkUriSafe = (src) => src
		.replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_')
		.replace(/=+$/m, '');
	const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
	const btoaPolyfill = (bin) => {
		let u32, c0, c1, c2, asc = '';
		const pad = bin.length % 3;
		for (let i = 0; i < bin.length;) {
			if ((c0 = bin.charCodeAt(i++)) > 255 ||
				(c1 = bin.charCodeAt(i++)) > 255 ||
				(c2 = bin.charCodeAt(i++)) > 255)
				throw new TypeError('invalid character found');
			u32 = (c0 << 16) | (c1 << 8) | c2;
			asc += b64chs[u32 >> 18 & 63] +
				b64chs[u32 >> 12 & 63] +
				b64chs[u32 >> 6 & 63] +
				b64chs[u32 & 63];
		}
		return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
	};
	const _btoa = _hasbtoa ? (bin) => btoa(bin) :
		_hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64') :
		btoaPolyfill;
	const _fromUint8Array = _hasBuffer ?
		(u8a) => Buffer.from(u8a).toString('base64') :
		(u8a) => {
			const maxargs = 0x1000;
			let strs = [];
			for (let i = 0, l = u8a.length; i < l; i += maxargs) {
				strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
			}
			return _btoa(strs.join(''));
		};
	const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
	const cb_utob = (c) => {
		if (c.length < 2) {
			var cc = c.charCodeAt(0);
			return cc < 0x80 ? c :
				cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6)) +
					_fromCC(0x80 | (cc & 0x3f))) :
				(_fromCC(0xe0 | ((cc >>> 12) & 0x0f)) +
					_fromCC(0x80 | ((cc >>> 6) & 0x3f)) +
					_fromCC(0x80 | (cc & 0x3f)));
		} else {
			var cc = 0x10000 +
				(c.charCodeAt(0) - 0xD800) * 0x400 +
				(c.charCodeAt(1) - 0xDC00);
			return (_fromCC(0xf0 | ((cc >>> 18) & 0x07)) +
				_fromCC(0x80 | ((cc >>> 12) & 0x3f)) +
				_fromCC(0x80 | ((cc >>> 6) & 0x3f)) +
				_fromCC(0x80 | (cc & 0x3f)));
		}
	};
	const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
	const utob = (u) => u.replace(re_utob, cb_utob);
	const _encode = _hasBuffer ?
		(s) => Buffer.from(s, 'utf8').toString('base64') :
		_TE ?
		(s) => _fromUint8Array(_TE.encode(s)) :
		(s) => _btoa(utob(s));
	const encode = (src, urlsafe = false) => urlsafe ?
		_mkUriSafe(_encode(src)) :
		_encode(src);
	const encodeURI = (src) => encode(src, true);
	const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
	const cb_btou = (cccc) => {
		switch (cccc.length) {
			case 4:
				var cp = ((0x07 & cccc.charCodeAt(0)) << 18) |
					((0x3f & cccc.charCodeAt(1)) << 12) |
					((0x3f & cccc.charCodeAt(2)) << 6) |
					(0x3f & cccc.charCodeAt(3)),
					offset = cp - 0x10000;
				return (_fromCC((offset >>> 10) + 0xD800) +
					_fromCC((offset & 0x3FF) + 0xDC00));
			case 3:
				return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12) |
					((0x3f & cccc.charCodeAt(1)) << 6) |
					(0x3f & cccc.charCodeAt(2)));
			default:
				return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6) |
					(0x3f & cccc.charCodeAt(1)));
		}
	};
	const btou = (b) => b.replace(re_btou, cb_btou);
	const atobPolyfill = (asc) => {
		asc = asc.replace(/\s+/g, '');
		if (!b64re.test(asc))
			throw new TypeError('malformed base64.');
		asc += '=='.slice(2 - (asc.length & 3));
		let u24, bin = '',
			r1, r2;
		for (let i = 0; i < asc.length;) {
			u24 = b64tab[asc.charAt(i++)] << 18 |
				b64tab[asc.charAt(i++)] << 12 |
				(r1 = b64tab[asc.charAt(i++)]) << 6 |
				(r2 = b64tab[asc.charAt(i++)]);
			bin += r1 === 64 ? _fromCC(u24 >> 16 & 255) :
				r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255) :
				_fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
		}
		return bin;
	};
	const _atob = _hasatob ? (asc) => atob(_tidyB64(asc)) :
		_hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary') :
		atobPolyfill;
	const _toUint8Array = _hasBuffer ?
		(a) => _U8Afrom(Buffer.from(a, 'base64')) :
		(a) => _U8Afrom(_atob(a), c => c.charCodeAt(0));
	const toUint8Array = (a) => _toUint8Array(_unURI(a));
	const _decode = _hasBuffer ?
		(a) => Buffer.from(a, 'base64').toString('utf8') :
		_TD ?
		(a) => _TD.decode(_toUint8Array(a)) :
		(a) => btou(_atob(a));
	const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
	const decode = (src) => _decode(_unURI(src));
	const isValid = (src) => {
		if (typeof src !== 'string')
			return false;
		const s = src.replace(/\s+/g, '').replace(/=+$/, '');
		return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s);
	};
	const _noEnum = (v) => {
		return {
			value: v,
			enumerable: false,
			writable: true,
			configurable: true
		};
	};
	const extendString = function () {
		const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));
		_add('fromBase64', function () {
			return decode(this);
		});
		_add('toBase64', function (urlsafe) {
			return encode(this, urlsafe);
		});
		_add('toBase64URI', function () {
			return encode(this, true);
		});
		_add('toBase64URL', function () {
			return encode(this, true);
		});
		_add('toUint8Array', function () {
			return toUint8Array(this);
		});
	};
	const extendUint8Array = function () {
		const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));
		_add('toBase64', function (urlsafe) {
			return fromUint8Array(this, urlsafe);
		});
		_add('toBase64URI', function () {
			return fromUint8Array(this, true);
		});
		_add('toBase64URL', function () {
			return fromUint8Array(this, true);
		});
	};
	const extendBuiltins = () => {
		extendString();
		extendUint8Array();
	};
	const gBase64 = {
		version: version,
		VERSION: VERSION,
		atob: _atob,
		atobPolyfill: atobPolyfill,
		btoa: _btoa,
		btoaPolyfill: btoaPolyfill,
		fromBase64: decode,
		toBase64: encode,
		encode: encode,
		encodeURI: encodeURI,
		encodeURL: encodeURI,
		utob: utob,
		btou: btou,
		decode: decode,
		isValid: isValid,
		fromUint8Array: fromUint8Array,
		toUint8Array: toUint8Array,
		extendString: extendString,
		extendUint8Array: extendUint8Array,
		extendBuiltins: extendBuiltins,
	};
	gBase64.Base64 = {};
	Object.keys(gBase64).forEach(k => gBase64.Base64[k] = gBase64[k]);
	return gBase64;
}));


**hex.js**
function Hex() {

}
Hex.encode = function (b, pos, len) {
    var hexCh = new Array(len * 2);
    var hexCode = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');

    for (var i = pos, j = 0; i < len + pos; i++, j++) {
        hexCh[j] = hexCode[(b[i] & 0xFF) >> 4];
        hexCh[++j] = hexCode[(b[i] & 0x0F)];
    }

    return hexCh.join('');
}

Hex.decode = function (hex) {

    if (hex == null || hex == '') {
        return null;
    }
    if (hex.length % 2 != 0) {
        return null;
    }

    var ascLen = hex.length / 2;
    var hexCh = this.toCharCodeArray(hex);
    var asc = new Array(ascLen);

    for (var i = 0; i < ascLen; i++) {

        if (hexCh[2 * i] >= 0x30 && hexCh[2 * i] <= 0x39) {
            asc[i] = ((hexCh[2 * i] - 0x30) << 4);
        } else if (hexCh[2 * i] >= 0x41 && hexCh[2 * i] <= 0x46) { //A-F : 0x41-0x46
            asc[i] = ((hexCh[2 * i] - 0x41 + 10) << 4);
        } else if (hexCh[2 * i] >= 0x61 && hexCh[2 * i] <= 0x66) { //a-f  : 0x61-0x66
            asc[i] = ((hexCh[2 * i] - 0x61 + 10) << 4);
        } else {
            return null;
        }

        if (hexCh[2 * i + 1] >= 0x30 && hexCh[2 * i + 1] <= 0x39) {
            asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x30));
        } else if (hexCh[2 * i + 1] >= 0x41 && hexCh[2 * i + 1] <= 0x46) {
            asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x41 + 10));
        } else if (hexCh[2 * i + 1] >= 0x61 && hexCh[2 * i + 1] <= 0x66) {
            asc[i] = (asc[i] | (hexCh[2 * i + 1] - 0x61 + 10));
        } else {
            return null;
        }


    }

    return asc;
}

Hex.utf8StrToHex = function (utf8Str) {
    var ens = encodeURIComponent(utf8Str);
    var es = unescape(ens);


    var esLen = es.length;

    // Convert
    var words = [];
    for (var i = 0; i < esLen; i++) {
        words[i] = (es.charCodeAt(i).toString(16));
    }
    return words.join('');
}

Hex.utf8StrToBytes = function (utf8Str) {
    var ens = encodeURIComponent(utf8Str);
    var es = unescape(ens);


    var esLen = es.length;

    // Convert
    var words = [];
    for (var i = 0; i < esLen; i++) {
        words[i] = es.charCodeAt(i);
    }
    return words;
}

Hex.hexToUtf8Str = function (utf8Str) {

    var utf8Byte = Hex.decode(utf8Str);
    var latin1Chars = [];
    for (var i = 0; i < utf8Byte.length; i++) {
        latin1Chars.push(String.fromCharCode(utf8Byte[i]));
    }
    return decodeURIComponent(escape(latin1Chars.join('')));
}

Hex.bytesToUtf8Str = function (bytesArray) {

    var utf8Byte = bytesArray;
    var latin1Chars = [];
    for (var i = 0; i < utf8Byte.length; i++) {
        latin1Chars.push(String.fromCharCode(utf8Byte[i]));
    }
    return decodeURIComponent(escape(latin1Chars.join('')));
}

Hex.toCharCodeArray = function (chs) {
    var chArr = new Array(chs.length);
    for (var i = 0; i < chs.length; i++) {
        chArr[i] = chs.charCodeAt(i);
    }
    return chArr;
}

hex2int = function (hex) {
    var len = hex.length,
        a = new Array(len),
        code;
    for (var i = 0; i < len; i++) {
        code = hex.charCodeAt(i);
        if (48 <= code && code < 58) {
            code -= 48;
        } else {
            code = (code & 0xdf) - 65 + 10;
        }
        a[i] = code;
    }

    return a.reduce(function (acc, c) {
        acc = 16 * acc + c;
        return acc;
    }, 0);
}

**sm3.js**
/**
 * 左补0到指定长度
 */
function leftPad(input, num) {
	if (input.length >= num) return input;

	return (new Array(num - input.length + 1)).join('0') + input
}

/**
 * 二进制转化为十六进制
 */
function binary2hex(binary) {
	const binaryLength = 8;
	let hex = '';
	for (let i = 0; i < binary.length / binaryLength; i++) {
		hex += leftPad(parseInt(binary.substr(i * binaryLength, binaryLength), 2).toString(16), 2);
	}
	return hex;
}

/**
 * 十六进制转化为二进制
 */
function hex2binary(hex) {
	const hexLength = 2;
	let binary = '';
	for (let i = 0; i < hex.length / hexLength; i++) {
		binary += leftPad(parseInt(hex.substr(i * hexLength, hexLength), 16).toString(2), 8);
	}
	return binary;
}

/**
 * 普通字符串转化为二进制
 */
function str2binary(str) {
	let binary = '';
	for (const ch of str) {
		binary += leftPad(ch.codePointAt(0).toString(2), 8);
	}
	return binary;
}

/**
 * 循环左移
 */
function rol(str, n) {
	return str.substring(n % str.length) + str.substr(0, n % str.length);
}

/**
 * 二进制运算
 */
function binaryCal(x, y, method) {
	const a = x || '';
	const b = y || '';
	const result = [];
	let prevResult;

	for (let i = a.length - 1; i >= 0; i--) { // 大端
		prevResult = method(a[i], b[i], prevResult);
		result[i] = prevResult[0];
	}
	return result.join('');
}

/**
 * 二进制异或运算
 */
function xor(x, y) {
	return binaryCal(x, y, (a, b) => [(a === b ? '0' : '1')]);
}

/**
 * 二进制与运算
 */
function and(x, y) {
	return binaryCal(x, y, (a, b) => [(a === '1' && b === '1' ? '1' : '0')]);
}

/**
 * 二进制或运算
 */
function or(x, y) {
	return binaryCal(x, y, (a, b) => [(a === '1' || b === '1' ? '1' : '0')]); // a === '0' && b === '0' ? '0' : '1'
}

/**
 * 二进制与运算
 */
function add(x, y) {
	const result = binaryCal(x, y, (a, b, prevResult) => {
		const carry = prevResult ? prevResult[1] : '0' || '0';

		// a,b不等时,carry不变,结果与carry相反
		// a,b相等时,结果等于原carry,新carry等于a
		if (a !== b) return [carry === '0' ? '1' : '0', carry];

		return [carry, a];
	});

	return result;
}

/**
 * 二进制非运算
 */
function not(x) {
	return binaryCal(x, undefined, a => [a === '1' ? '0' : '1']);
}

function calMulti(method) {
	return (...arr) => arr.reduce((prev, curr) => method(prev, curr));
}

/**
 * 压缩函数中的置换函数 P1(X) = X xor (X <<< 9) xor (X <<< 17)
 */
function P0(X) {
	return calMulti(xor)(X, rol(X, 9), rol(X, 17));
}

/**
 * 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
 */
function P1(X) {
	return calMulti(xor)(X, rol(X, 15), rol(X, 23));
}

function FF(X, Y, Z, j) {
	return j >= 0 && j <= 15 ? calMulti(xor)(X, Y, Z) : calMulti(or)(and(X, Y), and(X, Z), and(Y, Z));
}

function GG(X, Y, Z, j) {
	return j >= 0 && j <= 15 ? calMulti(xor)(X, Y, Z) : or(and(X, Y), and(not(X), Z));
}

function T(j) {
	return j >= 0 && j <= 15 ? hex2binary('79cc4519') : hex2binary('7a879d8a');
}

/**
 * 压缩函数
 */
function CF(V, Bi) {
	// 消息扩展
	const wordLength = 32;
	const W = [];
	const M = []; // W'

	// 将消息分组B划分为16个字W0, W1,…… ,W15 (字为长度为32的比特串)
	for (let i = 0; i < 16; i++) {
		W.push(Bi.substr(i * wordLength, wordLength));
	}

	// W[j] <- P1(W[j−16] xor W[j−9] xor (W[j−3] <<< 15)) xor (W[j−13] <<< 7) xor W[j−6]
	for (let j = 16; j < 68; j++) {
		W.push(calMulti(xor)(
			P1(calMulti(xor)(W[j - 16], W[j - 9], rol(W[j - 3], 15))),
			rol(W[j - 13], 7),
			W[j - 6]
		));
	}

	// W′[j] = W[j] xor W[j+4]
	for (let j = 0; j < 64; j++) {
		M.push(xor(W[j], W[j + 4]));
	}

	// 压缩
	const wordRegister = []; // 字寄存器
	for (let j = 0; j < 8; j++) {
		wordRegister.push(V.substr(j * wordLength, wordLength));
	}

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

	// 中间变量
	let SS1;
	let SS2;
	let TT1;
	let TT2;
	for (let j = 0; j < 64; j++) {
		SS1 = rol(calMulti(add)(rol(A, 12), E, rol(T(j), j)), 7);
		SS2 = xor(SS1, rol(A, 12));

		TT1 = calMulti(add)(FF(A, B, C, j), D, SS2, M[j]);
		TT2 = calMulti(add)(GG(E, F, G, j), H, SS1, W[j]);

		D = C;
		C = rol(B, 9);
		B = A;
		A = TT1;
		H = G;
		G = rol(F, 19);
		F = E;
		E = P0(TT2);
	}

	return xor([A, B, C, D, E, F, G, H].join(''), V);
}

function sm3_encrypt(str) {
	const binary = str2binary(str);

	// 填充
	const len = binary.length;

	// k是满足len + 1 + k = 448mod512的最小的非负整数
	let k = len % 512;

	// 如果 448 <= (512 % len) < 512,需要多补充 (len % 448) 比特'0'以满足总比特长度为512的倍数
	k = k >= 448 ? 512 - (k % 448) - 1 : 448 - k - 1;

	const m = `${binary}1${leftPad('', k)}${leftPad(len.toString(2), 64)}`.toString(); // k个0

	// 迭代压缩
	const n = (len + k + 65) / 512;

	let V = hex2binary('7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e');
	for (let i = 0; i <= n - 1; i++) {
		const B = m.substr(512 * i, 512);
		V = CF(V, B);
	}
	return binary2hex(V);
};




**sm4.js**
const DECRYPT = 0;
const ROUND = 32;
const BLOCK = 16;

const 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
];

const 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
];

function rotl(x, y) {
    return x << y | x >>> (32 - y);
}

function byteSub(a) {
    return (Sbox[a >>> 24 & 0xFF] & 0xFF) << 24 | (Sbox[a >>> 16 & 0xFF] & 0xFF) << 16 | (Sbox[a >>> 8 & 0xFF] & 0xFF) << 8 | (Sbox[a & 0xFF] & 0xFF);
}

function l1(b) {
    return b ^ rotl(b, 2) ^ rotl(b, 10) ^ rotl(b, 18) ^ rotl(b, 24);
}

function l2(b) {
    return b ^ rotl(b, 13) ^ rotl(b, 23);
}

function sms4Crypt(input, output, roundKey) {
    let r;
    let mid;
    let x = new Array(4);
    let tmp = new Array(4);
    for (let i = 0; i < 4; i++) {
        tmp[0] = input[0 + 4 * i] & 0xff;
        tmp[1] = input[1 + 4 * i] & 0xff;
        tmp[2] = input[2 + 4 * i] & 0xff;
        tmp[3] = input[3 + 4 * i] & 0xff;
        x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
    }

    for (r = 0; r < 32; r += 4) {
        mid = x[1] ^ x[2] ^ x[3] ^ roundKey[r + 0];
        mid = byteSub(mid);
        x[0] = x[0] ^ l1(mid); // x4

        mid = x[2] ^ x[3] ^ x[0] ^ roundKey[r + 1];
        mid = byteSub(mid);
        x[1] = x[1] ^ l1(mid); // x5

        mid = x[3] ^ x[0] ^ x[1] ^ roundKey[r + 2];
        mid = byteSub(mid);
        x[2] = x[2] ^ l1(mid); // x6

        mid = x[0] ^ x[1] ^ x[2] ^ roundKey[r + 3];
        mid = byteSub(mid);
        x[3] = x[3] ^ l1(mid); // x7
    }

    //Reverse
    for (let j = 0; j < 16; j += 4) {
        output[j] = x[3 - j / 4] >>> 24 & 0xff;
        output[j + 1] = x[3 - j / 4] >>> 16 & 0xff;
        output[j + 2] = x[3 - j / 4] >>> 8 & 0xff;
        output[j + 3] = x[3 - j / 4] & 0xff;
    }
}

function sms4KeyExt(key, roundKey, cryptFlag) {
    let r;
    let mid;
    let x = new Array(4);
    let tmp = new Array(4);

    for (let i = 0; i < 4; i++) {
        tmp[0] = key[0 + 4 * i] & 0xff;
        tmp[1] = key[1 + 4 * i] & 0xff;
        tmp[2] = key[2 + 4 * i] & 0xff;
        tmp[3] = key[3 + 4 * i] & 0xff;
        x[i] = tmp[0] << 24 | tmp[1] << 16 | tmp[2] << 8 | tmp[3];
    }

    x[0] ^= 0xa3b1bac6;
    x[1] ^= 0x56aa3350;
    x[2] ^= 0x677d9197;
    x[3] ^= 0xb27022dc;

    for (r = 0; r < 32; r += 4) {
        mid = x[1] ^ x[2] ^ x[3] ^ CK[r + 0];
        mid = byteSub(mid);
        roundKey[r + 0] = x[0] ^= l2(mid); // roundKey0 = K4

        mid = x[2] ^ x[3] ^ x[0] ^ CK[r + 1];
        mid = byteSub(mid);
        roundKey[r + 1] = x[1] ^= l2(mid); // roundKey1 = K5

        mid = x[3] ^ x[0] ^ x[1] ^ CK[r + 2];
        mid = byteSub(mid);
        roundKey[r + 2] = x[2] ^= l2(mid); // roundKey2 = K6

        mid = x[0] ^ x[1] ^ x[2] ^ CK[r + 3];
        mid = byteSub(mid);
        roundKey[r + 3] = x[3] ^= l2(mid); // roundKey3 = K7
    }

    // 解密时轮密钥使用顺序:roundKey31, roundKey30, ..., roundKey0
    if (cryptFlag === DECRYPT) {
        for (r = 0; r < 16; r++) {
            mid = roundKey[r];
            roundKey[r] = roundKey[31 - r];
            roundKey[31 - r] = mid;
        }
    }
}

function sm4(inArray, key, cryptFlag) {
    let outArray = [];
    let point = 0;
    let roundKey = new Array(ROUND);
    sms4KeyExt(key, roundKey, cryptFlag);

    let input = new Array(16);
    let output = new Array(16);

    let inLen = inArray.length;
    while (inLen >= BLOCK) {
        input = inArray.slice(point, point + 16);
        sms4Crypt(input, output, roundKey);

        for (let i = 0; i < BLOCK; i++) {
            outArray[point + i] = output[i];
        }

        inLen -= BLOCK;
        point += BLOCK;
    }

    return outArray;
}

function sm4_encrypt(inArray, key) {
    return sm4(inArray, key, 1);
};

function sm4_decrypt(inArray, key) {
    return sm4(inArray, key, 0);
};


  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值