赞
踩
<!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); };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。