欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-14 14:21:16
...
<!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);
};


相关标签: js 加密解密