目录
- 需求
- 【方法1】 – 使用 `sm4util` 依赖
- 【方法2】sm4.js引入
- 1. `/public/sm4.js`
- 2. body 标签上引入该文件
- 3. 使用 – ECB 模式加密
- 【方法3】
- 1. 本地写 js 文件
- 2. 使用 – ECB 模式加解密
需求
前端/后端使用
国密SM4
进行加密/解密,
【注意】前后端配合加解密时,需要我们自定义密钥
,一般由后端提供
【方法1】 – 使用 sm4util
依赖
下载
sm4util
依赖npm install sm4util
sm4util 依赖使用说明
使用 – ECB 模式加解密
/**** 【1】导入依赖 ****/ import { SM4Util } from 'sm4util'/**** 【2】使用(在改依赖中有使用说明) ****/// 1.使用默认密钥进行加密/解密var sm4 = new SM4Util()const miStr1 = sm4.encryptDefault_ECB('123') // sm4.encryptDefault_ECB(需要加密的字符串)console.log('miStr1----', miStr1)const jieStr1 = sm4.decryptDefault_ECB(miStr1) // sm4.decryptDefault_ECB(将字符串进行加密后生成的字符串)console.log('jieStr1----', jieStr1) // 123// 2.使用自定义密钥进行加密/解密(【注意】使用自定义密钥进行加密时,后端解密需要用相同的密钥进行解密 - 此处密钥可能不对)// var sm4 = new SM4Util()const miStr2 = sm4.encryptCustom_ECB('123', '93F3044B07393417A737E2CC389D01AF') // 加密sm4.encryptCustom_ECB(需要加密的字符串, 密钥)console.log('miStr2----', miStr2)const jieStr2 = sm4.decryptCustom_ECB(miStr2, '93F3044B07393417A737E2CC389D01AF') // 解密sm4.decryptCustom_ECB(将字符串进行加密后生成的字符串, 密钥)console.log('jieStr2----', jieStr2) // 123
后端代码参考:https://blog.csdn.net/qq_48922459/article/details/122130283
【方法2】sm4.js引入
这种办法好像只能使用默认密钥 key,不能自定义 key 我使用的自定义 key 会报错
"key error"
(也有可能是我的 密钥不对)
我使用自定义密钥 – 得改sm4.js 代码,详见SM4Util 函数
定义处被注释的代码
1. /public/sm4.js
/** * base64js * base64js.toByteArray(d.input) * base64js.fromByteArray(c); * 国密SM4加密算法 */;(function (r) {if (typeof exports === 'object' && typeof module !== 'undefined') {module.exports = r()} else {if (typeof define === 'function' && define.amd) {define([], r)} else {var eif (typeof window !== 'undefined') {e = window} else {if (typeof global !== 'undefined') {e = global} else {if (typeof self !== 'undefined') {e = self} else {e = this}}}e.base64js = r()}}})(function () {var r, e, treturn (function r(e, t, n) {function o(i, a) {if (!t[i]) {if (!e[i]) {var u = typeof require == 'function' && requireif (!a && u) {return u(i, !0)}if (f) {return f(i, !0)}var d = new Error("Cannot find module '" + i + "'")throw ((d.code = 'MODULE_NOT_FOUND'), d)}var c = (t[i] = { exports: {} })e[i][0].call(c.exports,function (r) {var t = e[i][1][r]return o(t " />: r)},c,c.exports,r,e,t,n)}return t[i].exports}var f = typeof require == 'function' && requirefor (var i = 0; i < n.length; i++) {o(n[i])}return o})({'/': [function (r, e, t) {t.byteLength = ct.toByteArray = vt.fromByteArray = svar n = []var o = []var f = typeof Uint8Array !== 'undefined' ? Uint8Array : Arrayvar i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'for (var a = 0, u = i.length; a < u; ++a) {n[a] = i[a]o[i.charCodeAt(a)] = a}o['-'.charCodeAt(0)] = 62o['_'.charCodeAt(0)] = 63function d(r) {var e = r.lengthif (e % 4 > 0) {throw new Error('Invalid string. Length must be a multiple of 4')}return r[e - 2] === '=' ? 2 : r[e - 1] === '=' ? 1 : 0}function c(r) {return (r.length * 3) / 4 - d(r)}function v(r) {var e, t, n, i, avar u = r.lengthi = d(r)a = new f((u * 3) / 4 - i)t = i > 0 ? u - 4 : uvar c = 0for (e = 0; e < t; e += 4) {n =(o[r.charCodeAt(e)] << 18) |(o[r.charCodeAt(e + 1)] << 12) |(o[r.charCodeAt(e + 2)] << 6) |o[r.charCodeAt(e + 3)]a[c++] = (n >> 16) & 255a[c++] = (n >> 8) & 255a[c++] = n & 255}if (i === 2) {n = (o[r.charCodeAt(e)] << 2) | (o[r.charCodeAt(e + 1)] >> 4)a[c++] = n & 255} else {if (i === 1) {n = (o[r.charCodeAt(e)] << 10) | (o[r.charCodeAt(e + 1)] << 4) | (o[r.charCodeAt(e + 2)] >> 2)a[c++] = (n >> 8) & 255a[c++] = n & 255}}return a}function l(r) {return n[(r >> 18) & 63] + n[(r >> 12) & 63] + n[(r >> 6) & 63] + n[r & 63]}function h(r, e, t) {var nvar o = []for (var f = e; f < t; f += 3) {n = (r[f] << 16) + (r[f + 1] << 8) + r[f + 2]o.push(l(n))}return o.join('')}function s(r) {var evar t = r.lengthvar o = t % 3var f = ''var i = []var a = 16383for (var u = 0, d = t - o; u < d; u += a) {i.push(h(r, u, u + a > d ? d : u + a))}if (o === 1) {e = r[t - 1]f += n[e >> 2]f += n[(e << 4) & 63]f += '=='} else {if (o === 2) {e = (r[t - 2] << 8) + r[t - 1]f += n[e >> 10]f += n[(e >> 4) & 63]f += n[(e << 2) & 63]f += '='}}i.push(f)return i.join('')}},{}]},{},[])('/')})/** * 国密SM4加密算法 * @author wzk * @email 1216113487@qq.com * @company 中科软 */function SM4_Context() {this.mode = 1this.isPadding = truethis.sk = new Array(32)}function SM4() {this.SM4_ENCRYPT = 1this.SM4_DECRYPT = 0var SboxTable = [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 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]this.GET_ULONG_BE = function (b, i) {return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | (b[i + 3] & 0xff & 0xffffffff)}this.PUT_ULONG_BE = function (n, b, i) {var t1 = 0xff & (n >> 24)var t2 = 0xff & (n >> 16)var t3 = 0xff & (n >> 8)var t4 = 0xff & nb[i] = t1 > 128 ? t1 - 256 : t1b[i + 1] = t2 > 128 ? t2 - 256 : t2b[i + 2] = t3 > 128 ? t3 - 256 : t3b[i + 3] = t4 > 128 ? t4 - 256 : t4}this.SHL = function (x, n) {return (x & 0xffffffff) << n}this.ROTL = function (x, n) {var s = this.SHL(x, n)var ss = x >> (32 - n)return this.SHL(x, n) | (x >> (32 - n))}this.sm4Lt = function (ka) {var bb = 0var c = 0var a = new Array(4)var b = new Array(4)this.PUT_ULONG_BE(ka, a, 0)b[0] = this.sm4Sbox(a[0])b[1] = this.sm4Sbox(a[1])b[2] = this.sm4Sbox(a[2])b[3] = this.sm4Sbox(a[3])bb = this.GET_ULONG_BE(b, 0)c = bb ^ this.ROTL(bb, 2) ^ this.ROTL(bb, 10) ^ this.ROTL(bb, 18) ^ this.ROTL(bb, 24)return c}this.sm4F = function (x0, x1, x2, x3, rk) {return x0 ^ this.sm4Lt(x1 ^ x2 ^ x3 ^ rk)}this.sm4CalciRK = function (ka) {var bb = 0var rk = 0var a = new Array(4)var b = new Array(4)this.PUT_ULONG_BE(ka, a, 0)b[0] = this.sm4Sbox(a[0])b[1] = this.sm4Sbox(a[1])b[2] = this.sm4Sbox(a[2])b[3] = this.sm4Sbox(a[3])bb = this.GET_ULONG_BE(b, 0)rk = bb ^ this.ROTL(bb, 13) ^ this.ROTL(bb, 23)return rk}this.sm4Sbox = function (inch) {var i = inch & 0xffvar retVal = SboxTable[i]return retVal > 128 ? retVal - 256 : retVal}this.sm4_setkey_enc = function (ctx, key) {if (ctx == null) {alert('ctx is null!')return false}console.log('key----', key)if (key == null || key.length != 16) {alert('key error!')return false}ctx.mode = this.SM4_ENCRYPTthis.sm4_setkey(ctx.sk, key)}this.sm4_setkey = function (SK, key) {var MK = new Array(4)var k = new Array(36)var i = 0MK[0] = this.GET_ULONG_BE(key, 0)MK[1] = this.GET_ULONG_BE(key, 4)MK[2] = this.GET_ULONG_BE(key, 8)MK[3] = this.GET_ULONG_BE(key, 12)k[0] = MK[0] ^ FK[0]k[1] = MK[1] ^ FK[1]k[2] = MK[2] ^ FK[2]k[3] = MK[3] ^ FK[3]for (var i = 0; i < 32; i++) {k[i + 4] = k[i] ^ this.sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i])SK[i] = k[i + 4]}}this.padding = function (input, mode) {if (input == null) {return null}var ret = nullif (mode == this.SM4_ENCRYPT) {var p = parseInt(16 - (input.length % 16))ret = input.slice(0)for (var i = 0; i < p; i++) {ret[input.length + i] = p}} else {var p = input[input.length - 1]ret = input.slice(0, input.length - p)}return ret}this.sm4_one_round = function (sk, input, output) {var i = 0var ulbuf = new Array(36)ulbuf[0] = this.GET_ULONG_BE(input, 0)ulbuf[1] = this.GET_ULONG_BE(input, 4)ulbuf[2] = this.GET_ULONG_BE(input, 8)ulbuf[3] = this.GET_ULONG_BE(input, 12)while (i < 32) {ulbuf[i + 4] = this.sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i])i++}this.PUT_ULONG_BE(ulbuf[35], output, 0)this.PUT_ULONG_BE(ulbuf[34], output, 4)this.PUT_ULONG_BE(ulbuf[33], output, 8)this.PUT_ULONG_BE(ulbuf[32], output, 12)}this.sm4_crypt_ecb = function (ctx, input) {if (input == null) {alert('input is null!')}if (ctx.isPadding && ctx.mode == this.SM4_ENCRYPT) {input = this.padding(input, this.SM4_ENCRYPT)}var i = 0var length = input.lengthvar bous = new Array()for (; length > 0; length -= 16) {var out = new Array(16)var ins = input.slice(i * 16, 16 * (i + 1))this.sm4_one_round(ctx.sk, ins, out)bous = bous.concat(out)i++}var output = bousif (ctx.isPadding && ctx.mode == this.SM4_DECRYPT) {output = this.padding(output, this.SM4_DECRYPT)}for (var i = 0; i < output.length; i++) {if (output[i] < 0) {output[i] = output[i] + 256}}return output}this.sm4_crypt_cbc = function (ctx, iv, input) {if (iv == null || iv.length != 16) {alert('iv error!')}if (input == null) {alert('input is null!')}if (ctx.isPadding && ctx.mode == this.SM4_ENCRYPT) {input = this.padding(input, this.SM4_ENCRYPT)}var i = 0var length = input.lengthvar bous = new Array()if (ctx.mode == this.SM4_ENCRYPT) {var k = 0for (; length > 0; length -= 16) {var out = new Array(16)var out1 = new Array(16)var ins = input.slice(k * 16, 16 * (k + 1))for (i = 0; i < 16; i++) {out[i] = ins[i] ^ iv[i]}this.sm4_one_round(ctx.sk, out, out1)iv = out1.slice(0, 16)bous = bous.concat(out1)k++}} else {var temp = []var k = 0for (; length > 0; length -= 16) {var out = new Array(16)var out1 = new Array(16)var ins = input.slice(k * 16, 16 * (k + 1))temp = ins.slice(0, 16)sm4_one_round(ctx.sk, ins, out)for (i = 0; i < 16; i++) {out1[i] = out[i] ^ iv[i]}iv = temp.slice(0, 16)bous = bous.concat(out1)k++}}var output = bousif (ctx.isPadding && ctx.mode == this.SM4_DECRYPT) {output = this.padding(output, this.SM4_DECRYPT)}for (var i = 0; i < output.length; i++) {if (output[i] < 0) {output[i] = output[i] + 256}}return output}}// function SM4Util(key = '1111111111111111') {function SM4Util() {console.log('SM4Util key----', key)// 和后端key一致(key为密钥)// this.secretKey = keythis.secretKey = '1111111111111111'// 当时用CBC模式的时候this.iv = '1111111111111111'this.hexString = false// ECB模式加密this.encryptData_ECB = function (plainText) {try {var sm4 = new SM4()var ctx = new SM4_Context()ctx.isPadding = truectx.mode = sm4.SM4_ENCRYPTvar keyBytes = stringToByte(this.secretKey)sm4.sm4_setkey_enc(ctx, keyBytes)var encrypted = sm4.sm4_crypt_ecb(ctx, stringToByte(plainText))var cipherText = base64js.fromByteArray(encrypted)if (cipherText != null && cipherText.trim().length > 0) {cipherText.replace(/(\s*|\t|\r|\n)/g, '')}return cipherText} catch (e) {console.error(e)return null}}// CBC模式加密this.encryptData_CBC = function (plainText) {try {var sm4 = new SM4()var ctx = new SM4_Context()ctx.isPadding = truectx.mode = sm4.SM4_ENCRYPTvar keyBytes = stringToByte(this.secretKey)var ivBytes = stringToByte(this.iv)sm4.sm4_setkey_enc(ctx, keyBytes)var encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, stringToByte(plainText))var cipherText = base64js.fromByteArray(encrypted)if (cipherText != null && cipherText.trim().length > 0) {cipherText.replace(/(\s*|\t|\r|\n)/g, '')}return cipherText} catch (e) {console.error(e)return null}}stringToByte = function (str) {var bytes = new Array()var len, clen = str.lengthfor (var i = 0; i < len; i++) {c = str.charCodeAt(i)if (c >= 0x010000 && c <= 0x10ffff) {bytes.push(((c >> 18) & 0x07) | 0xf0)bytes.push(((c >> 12) & 0x3f) | 0x80)bytes.push(((c >> 6) & 0x3f) | 0x80)bytes.push((c & 0x3f) | 0x80)} else if (c >= 0x000800 && c <= 0x00ffff) {bytes.push(((c >> 12) & 0x0f) | 0xe0)bytes.push(((c >> 6) & 0x3f) | 0x80)bytes.push((c & 0x3f) | 0x80)} else if (c >= 0x000080 && c <= 0x0007ff) {bytes.push(((c >> 6) & 0x1f) | 0xc0)bytes.push((c & 0x3f) | 0x80)} else {bytes.push(c & 0xff)}}console.log('bytes----', bytes)return bytes}byteToString = function (arr) {if (typeof arr === 'string') {return arr}var str = '',_arr = arrfor (var i = 0; i < _arr.length; i++) {var one = _arr[i].toString(2),v = one.match(/^1+?(?=0)/)if (v && one.length == 8) {var bytesLength = v[0].lengthvar store = _arr[i].toString(2).slice(7 - bytesLength)for (var st = 1; st < bytesLength; st++) {store += _arr[st + i].toString(2).slice(2)}str += String.fromCharCode(parseInt(store, 2))i += bytesLength - 1} else {str += String.fromCharCode(_arr[i])}}return str}}
2. body 标签上引入该文件
<script src="/sm4.js"></script><body></body>
3. 使用 – ECB 模式加密
// 加密 - 使用默认秘钥 1111111111111111var sm4 = new SM4Util();sm4.encryptData_ECB('123');// 加密 - 使用自定义秘钥 93F3044B07393417A737E2CC389D01AF (需将 sm4.js 文件中SM4Util 函数处注释的代码打开)var sm4 = new SM4Util('93F3044B07393417A737E2CC389D01AF');sm4.encryptData_ECB('123');// 后端解密的好像对不上,
该加密办法参考博客 https://blog.csdn.net/wzk_blog/article/details/122668114
【方法3】
1. 本地写 js 文件
@/utils/SM4Util/index.js
let base64js = require('./base64js')let Hex = require('./hex')let SM4 = require('./sm4')function SM4Util() {}/** * sm4 ecb 加密 * @param utf8Str * @param utf8Key */SM4Util.sm4ECBEncrypt = function (utf8Str, utf8Key) {if (!utf8Key) {utf8Key = 'zzfh!@#$QazxWsxc'}let sm4 = new SM4()let keyBytes = Hex.utf8StrToBytes(utf8Key)let contentBytes = Hex.utf8StrToBytes(utf8Str)let cipher = sm4.encrypt_ecb(keyBytes, contentBytes)return base64js.fromByteArray(cipher)}/** * sm4 ecb 解密 * @param utf8Str * @param utf8Key */SM4Util.sm4ECBDecrypt = function (base64Str, utf8Key) {if (!utf8Key) {utf8Key = 'zzfh!@#$QazxWsxc'}let sm4 = new SM4()let keyBytes = Hex.utf8StrToBytes(utf8Key)let contentBytes = base64js.toByteArray(base64Str)let plain = sm4.decrypt_ecb(keyBytes, contentBytes)return Hex.bytesToUtf8Str(plain)}/** * sm4 cbc 加密 * @param utf8Str * @param utf8Key * @param utf8Iv */SM4Util.sm4CBCEncrypt = function (utf8Str, utf8Key, utf8Iv) {if (!utf8Key) {utf8Key = 'cmbtest1cmbtest1'}if (!utf8Iv) {utf8Iv = 'cmbtest1cmbtest1'}let sm4 = new SM4()let keyBytes = Hex.utf8StrToBytes(utf8Key)let ivBytes = Hex.utf8StrToBytes(utf8Iv)let contentBytes = Hex.utf8StrToBytes(utf8Str)let cipher = sm4.encrypt_cbc(keyBytes, ivBytes, contentBytes)return base64js.fromByteArray(cipher)}/** * sm4 cbc 解密 * @param utf8Str * @param utf8Key * @param utf8Iv */SM4Util.sm4CBCDecrypt = function (base64Str, utf8Key, utf8Iv) {if (!utf8Key) {utf8Key = 'cmbtest1cmbtest1'}if (!utf8Iv) {utf8Iv = 'cmbtest1cmbtest1'}let sm4 = new SM4()let keyBytes = Hex.utf8StrToBytes(utf8Key)let ivBytes = Hex.utf8StrToBytes(utf8Iv)let contentBytes = base64js.toByteArray(base64Str)let plain = sm4.decrypt_cbc(keyBytes, ivBytes, contentBytes)return Hex.bytesToUtf8Str(plain)}module.exports = SM4Util
@/utils/SM4Util/base64js.js
/** * base64js * base64js.toByteArray(utf8Str) * base64js.fromByteArray(bytes); */;(function (r) {if (typeof exports === 'object' && typeof module !== 'undefined') {module.exports = r()} else {if (typeof define === 'function' && define.amd) {define([], r)} else {var eif (typeof window !== 'undefined') {e = window} else {if (typeof global !== 'undefined') {e = global} else {if (typeof self !== 'undefined') {e = self} else {e = this}}}e.base64js = r()}}})(function () {var r, e, treturn (function r(e, t, n) {function o(i, a) {if (!t[i]) {if (!e[i]) {var u = typeof require == 'function' && requireif (!a && u) {return u(i, !0)}if (f) {return f(i, !0)}var d = new Error("Cannot find module '" + i + "'")throw ((d.code = 'MODULE_NOT_FOUND'), d)}var c = (t[i] = {exports: {}})e[i][0].call(c.exports,function (r) {var t = e[i][1][r]return o(t ? t : r)},c,c.exports,r,e,t,n)}return t[i].exports}var f = typeof require == 'function' && requirefor (var i = 0; i < n.length; i++) {o(n[i])}return o})({'/': [function (r, e, t) {t.byteLength = ct.toByteArray = vt.fromByteArray = svar n = []var o = []var f = typeof Uint8Array !== 'undefined' ? Uint8Array : Arrayvar i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'for (var a = 0, u = i.length; a < u; ++a) {n[a] = i[a]o[i.charCodeAt(a)] = a}o['-'.charCodeAt(0)] = 62o['_'.charCodeAt(0)] = 63function d(r) {var e = r.lengthif (e % 4 > 0) {throw new Error('Invalid string. Length must be a multiple of 4')}return r[e - 2] === '=' ? 2 : r[e - 1] === '=' ? 1 : 0}function c(r) {return (r.length * 3) / 4 - d(r)}function v(r) {var e, t, n, i, avar u = r.lengthi = d(r)a = new f((u * 3) / 4 - i)t = i > 0 ? u - 4 : uvar c = 0for (e = 0; e < t; e += 4) {n =(o[r.charCodeAt(e)] << 18) |(o[r.charCodeAt(e + 1)] << 12) |(o[r.charCodeAt(e + 2)] << 6) |o[r.charCodeAt(e + 3)]a[c++] = (n >> 16) & 255a[c++] = (n >> 8) & 255a[c++] = n & 255}if (i === 2) {n = (o[r.charCodeAt(e)] << 2) | (o[r.charCodeAt(e + 1)] >> 4)a[c++] = n & 255} else {if (i === 1) {n = (o[r.charCodeAt(e)] << 10) | (o[r.charCodeAt(e + 1)] << 4) | (o[r.charCodeAt(e + 2)] >> 2)a[c++] = (n >> 8) & 255a[c++] = n & 255}}return a}function l(r) {return n[(r >> 18) & 63] + n[(r >> 12) & 63] + n[(r >> 6) & 63] + n[r & 63]}function h(r, e, t) {var nvar o = []for (var f = e; f < t; f += 3) {n = (r[f] << 16) + (r[f + 1] << 8) + r[f + 2]o.push(l(n))}return o.join('')}function s(r) {var evar t = r.lengthvar o = t % 3var f = ''var i = []var a = 16383for (var u = 0, d = t - o; u < d; u += a) {i.push(h(r, u, u + a > d ? d : u + a))}if (o === 1) {e = r[t - 1]f += n[e >> 2]f += n[(e << 4) & 63]f += '=='} else {if (o === 2) {e = (r[t - 2] << 8) + r[t - 1]f += n[e >> 10]f += n[(e >> 4) & 63]f += n[(e << 2) & 63]f += '='}}i.push(f)return i.join('')}},{}]},{},[])('/')})
@/utils/SM4Util/hex.js
function Hex() {}/** * 数组转为16进制字符串 * @param b数组 * @param pos指定位置 * @param len长度 * @returns {string} */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('')}/** * 16进制字符串转为字节数组 * @param hex * @returns {any[]|null} */Hex.decode = function (hex) {if (hex == null || hex == '') {return null}if (hex.length % 2 != 0) {return null}var ascLen = hex.length / 2var 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-0x46asc[i] = (hexCh[2 * i] - 0x41 + 10) << 4} else if (hexCh[2 * i] >= 0x61 && hexCh[2 * i] <= 0x66) {//a-f: 0x61-0x66asc[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}/** * utf8字符串转为字节数组 * @param utf8Str * @returns {[]} */Hex.utf8StrToBytes = function (utf8Str) {var ens = encodeURIComponent(utf8Str)var es = unescape(ens)var esLen = es.length// Convertvar words = []for (var i = 0; i < esLen; i++) {words[i] = es.charCodeAt(i)}return words}/** * 字节数组转为utf8字符串 * @param bytesArray * @returns {string} */Hex.bytesToUtf8Str = function (bytesArray) {var utf8Byte = bytesArrayvar latin1Chars = []for (var i = 0; i < utf8Byte.length; i++) {latin1Chars.push(String.fromCharCode(utf8Byte[i]))}return decodeURIComponent(escape(latin1Chars.join('')))}/** * 16进制字符串转为utf8字符串 * @param utf8Str * @returns {string} */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('')))}/** * utf8字符串转为16进制字符串 * @param utf8Str * @returns {string} */Hex.utf8StrToHex = function (utf8Str) {var ens = encodeURIComponent(utf8Str)var es = unescape(ens)var esLen = es.length// Convertvar words = []for (var i = 0; i < esLen; i++) {words[i] = es.charCodeAt(i).toString(16)}return words.join('')}/** * 字符串中每个字符转为数组中每个元素,数字,字母同Hex.utf8StrToBytes()方法 * @param chs * @returns {any[]} */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}module.exports = Hex
@/utils/SM4Util/sm4.js
/* * sm4-1.0.js * * Copyright (c) 2019 RuXing Liang *//** * @name sm4-1.0.js * @author RuXing Liang * @version 1.0.0 (2019-04-19) */function SM4() {this.sbox = new Array(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)this.fk = new Array(0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc)this.ck = new Array(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)}SM4.prototype = {expandKey: function (key) {var k = new Array(36)var mk = byteArrayToIntArray(key)k[0] = mk[0] ^ this.fk[0]k[1] = mk[1] ^ this.fk[1]k[2] = mk[2] ^ this.fk[2]k[3] = mk[3] ^ this.fk[3]var rk = new Array(32)for (var i = 0; i < 32; i++) {k[i + 4] = k[i] ^ this.T1(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ this.ck[i])rk[i] = k[i + 4]}return rk},T1: function (ta) {var rk = 0var b = new Array(4)var a = intToByte(ta)b[0] = this.sbox[a[0] & 0xff]b[1] = this.sbox[a[1] & 0xff]b[2] = this.sbox[a[2] & 0xff]b[3] = this.sbox[a[3] & 0xff]var bint = byteToInt(b, 0)var rk = bint ^ ((bint << 13) | (bint >>> (32 - 13))) ^ ((bint << 23) | (bint >>> (32 - 23)))return rk},one_encrypt: function (rk, data) {var x = new Array(36)x[0] = byteToInt(data, 0)x[1] = byteToInt(data, 4)x[2] = byteToInt(data, 8)x[3] = byteToInt(data, 12)for (var i = 0; i < 32; i++) {x[i + 4] = x[i] ^ this.T0(x[i + 1] ^ x[i + 2] ^ x[i + 3] ^ rk[i])}var tmpx = new Array(4)for (var i = 35; i >= 32; i--) {tmpx[35 - i] = x[i]}var xbyte = intArrayToByteArray(tmpx)return xbyte},T0: function (ta) {var a = intToByte(ta)var b = new Array(4)b[0] = this.sbox[a[0] & 0xff]b[1] = this.sbox[a[1] & 0xff]b[2] = this.sbox[a[2] & 0xff]b[3] = this.sbox[a[3] & 0xff]var bint = byteToInt(b, 0)var c =bint ^((bint << 2) | (bint >>> (32 - 2))) ^((bint << 10) | (bint >>> (32 - 10))) ^((bint << 18) | (bint >>> (32 - 18))) ^((bint << 24) | (bint >>> (32 - 24)))return c},pkcs7padding: function (input, mode) {if (input == null) {return null}var ret = nullif (mode == 1) {//填充var p = 16 - (input.length % 16)ret = new Array(input.length + p)arrayCopy(input, 0, ret, 0, input.length)for (var i = 0; i < p; i++) {ret[input.length + i] = p}} //去除填充else {var p = input[input.length - 1]ret = new Array(input.length - p)arrayCopy(input, 0, ret, 0, input.length - p)}return ret},/** * * @param key 字节数组 * @param data 字节数组 * @returns {any[]|null} */encrypt_ecb: function (key, data) {if (key == undefined || key == null || key.length % 16 != 0) {console.log('sm4 key is error!')return null}if (data == undefined || data == null || data.length <= 0) {console.log('data is error!')return null}var rk = this.expandKey(key)/*if(debug){var rkb = intArrayToByteArray(rk);console.log(Hex.encode(rkb,0,rkb.length));}*/var blockLen = 16var loop = parseInt(data.length / blockLen) //注意不能整除会有小数,要取整var cipher = new Array((loop + 1) * blockLen)var tmp = new Array(blockLen)var oneCipher = nullfor (var i = 0; i < loop; i++) {arrayCopy(data, i * blockLen, tmp, 0, blockLen)oneCipher = this.one_encrypt(rk, tmp)arrayCopy(oneCipher, 0, cipher, i * blockLen, blockLen)}var lessData = new Array(data.length % blockLen)if (lessData.length > 0) {arrayCopy(data, loop * blockLen, lessData, 0, data.length % blockLen)}var padding = this.pkcs7padding(lessData, 1)oneCipher = this.one_encrypt(rk, padding)arrayCopy(oneCipher, 0, cipher, loop * blockLen, blockLen)return cipher},/** * * @param key字节数组 * @param data字节数组 * @returns {any[]|null} */decrypt_ecb: function (key, data) {if (key == undefined || key == null || key.length % 16 != 0) {console.log('sm4 key is error!')return null}if (data == undefined || data == null || data.length % 16 != 0) {console.log('data is error!')return null}var rk = this.expandKey(key)var nrk = new Array(32)for (var i = 0; i < rk.length; i++) {nrk[i] = rk[32 - i - 1]}var blockLen = 16var loop = data.length / blockLen - 1var tmp = new Array(blockLen)var onePlain = nullvar plain = null//先解密最后一部分,确定数据长度arrayCopy(data, loop * blockLen, tmp, 0, blockLen)onePlain = this.one_encrypt(nrk, tmp)var lastPart = this.pkcs7padding(onePlain, 0)plain = new Array(loop * blockLen + lastPart.length)arrayCopy(lastPart, 0, plain, loop * blockLen, lastPart.length)//解密剩下部分数据for (var i = 0; i < loop; i++) {arrayCopy(data, i * blockLen, tmp, 0, blockLen)onePlain = this.one_encrypt(nrk, tmp)arrayCopy(onePlain, 0, plain, i * blockLen, blockLen)}return plain},encrypt_cbc: function (key, iv, data) {if (key == undefined || key == null || key.length % 16 != 0) {console.log('sm4 key is error!')return null}if (data == undefined || data == null || data.length <= 0) {console.log('data is error!')return null}if (iv == undefined || iv == null || iv.length % 16 != 0) {console.log('iv is error!')return null}var rk = this.expandKey(key)var blockLen = 16var loop = parseInt(data.length / blockLen) //注意不能整除会有小数,要取整var cipher = new Array((loop + 1) * blockLen)var tmp = new Array(blockLen)var oneCipher = nullfor (var i = 0; i < loop; i++) {arrayCopy(data, i * blockLen, tmp, 0, blockLen)for (var j = 0; j < blockLen; j++) {tmp[j] = tmp[j] ^ iv[j]}iv = this.one_encrypt(rk, tmp)arrayCopy(iv, 0, cipher, i * blockLen, blockLen)}var lessData = new Array(data.length % blockLen)if (lessData.length > 0) {arrayCopy(data, loop * blockLen, lessData, 0, data.length % blockLen)}var padding = this.pkcs7padding(lessData, 1)for (var i = 0; i < blockLen; i++) {padding[i] = padding[i] ^ iv[i]}iv = this.one_encrypt(rk, padding)arrayCopy(iv, 0, cipher, loop * blockLen, blockLen)return cipher},decrypt_cbc: function (key, iv, data) {if (key == undefined || key == null || key.length % 16 != 0) {console.log('sm4 key is error!')return null}if (data == undefined || data == null || data.length % 16 != 0) {console.log('data is error!')return null}if (iv == undefined || iv == null || iv.length % 16 != 0) {console.log('iv is error!')return null}var rk = this.expandKey(key)var nrk = new Array(32)for (var i = 0; i < rk.length; i++) {nrk[i] = rk[32 - i - 1]}var blockLen = 16var loop = data.length / blockLenvar tmp = new Array(blockLen)var onePlain = nullvar plain = null//解密plain = new Array(data.length)for (var i = 0; i < loop; i++) {arrayCopy(data, i * blockLen, tmp, 0, blockLen)onePlain = this.one_encrypt(nrk, tmp)for (var j = 0; j < blockLen; j++) {onePlain[j] = onePlain[j] ^ iv[j]}arrayCopy(tmp, 0, iv, 0, blockLen)arrayCopy(onePlain, 0, plain, i * blockLen, blockLen)}//去填充,确定数据长度//arrayCopy(data,data.length-blockLen,tmp,0,blockLen);var lastPart = this.pkcs7padding(onePlain, 0)var realPlain = new Array(plain.length - blockLen + lastPart.length)arrayCopy(plain, 0, realPlain, 0, plain.length - blockLen)arrayCopy(lastPart, 0, realPlain, plain.length - blockLen, lastPart.length)return realPlain}}///工具类//* * 数组复制 */function arrayCopy(src, pos1, dest, pos2, len) {var realLen = lenif (pos1 + len > src.length && pos2 + len <= dest.length) {realLen = src.length - pos1} else if (pos2 + len > dest.length && pos1 + len <= src.length) {realLen = dest.length - pos2} else if (pos1 + len <= src.length && pos2 + len <= dest.length) {realLen = len} else if (dest.length < src.length) {realLen = dest.length - pos2} else {realLen = src.length - pos2}for (var i = 0; i < realLen; i++) {dest[i + pos2] = src[i + pos1]}}/* * 长整型转成字节,一个长整型为8字节 * 返回:字节数组 */function longToByte(num) {//TODO 这里目前只转换了低四字节,因为js没有长整型,得要封装return new Array(0,0,0,0,(num >> 24) & 0x000000ff,(num >> 16) & 0x000000ff,(num >> 8) & 0x000000ff,num & 0x000000ff)}/* * int数转成byte数组 * 事实上只不过转成byte大小的数,实际占用空间还是4字节 * 返回:字节数组 */function intToByte(num) {return new Array((num >> 24) & 0x000000ff, (num >> 16) & 0x000000ff, (num >> 8) & 0x000000ff, num & 0x000000ff)}/* * int数组转成byte数组,一个int数值转成四个byte * 返回:byte数组 */function intArrayToByteArray(nums) {var b = new Array(nums.length * 4)for (var i = 0; i < nums.length; i++) {arrayCopy(intToByte(nums[i]), 0, b, i * 4, 4)}return b}/* * byte数组转成int数值 * 返回:int数值 */function byteToInt(b, pos) {if (pos + 3 < b.length) {return (b[pos] << 24) | (b[pos + 1] << 16) | (b[pos + 2] << 8) | b[pos + 3]} else if (pos + 2 < b.length) {return (b[pos + 1] << 16) | (b[pos + 2] << 8) | b[pos + 3]} else if (pos + 1 < b.length) {return (b[pos] << 8) | b[pos + 1]} else {return b[pos]}}/* * byte数组转成int数组,每四个字节转成一个int数值 * */function byteArrayToIntArray(b) {// var arrLen = b.length%4==0 ? b.length/4:b.length/4+1;var arrLen = Math.ceil(b.length / 4) //向上取整var out = new Array(arrLen)for (var i = 0; i < b.length; i++) {b[i] = b[i] & 0xff //避免负数造成影响}for (var i = 0; i < out.length; i++) {out[i] = byteToInt(b, i * 4)}return out}module.exports = SM4
2. 使用 – ECB 模式加解密
import SM4Util from '@/utils/SM4Util'const miStr = SM4Util.sm4ECBEncrypt('13012345678', '93F3044B07393417') // 加密 SM4Util.sm4ECBEncrypt(需要加密的字符串, 密钥)console.log('miStr----', miStr) // 8O/HeW8uoXU/CkcDaXRpxQ==const jieStr = SM4Util.sm4ECBDecrypt(miStr, '93F3044B07393417') // 解密 SM4Util.sm4ECBDecrypt(加密后的字符串, 密钥)console.log('jieStr----', jieStr) // 13012345678// 加密后传给后端进行解密