前端使用国密SM4进行加密

news2025/1/13 14:33:28

目录

  • 需求
  • 【方法1】 - 使用 `sm4util` 依赖
  • 【方法2】sm4.js引入
    • 1. `/public/sm4.js`
    • 2. body 标签上引入该文件
    • 3. 使用 - ECB 模式加密
  • 【方法3】
    • 1. 本地写 js 文件
    • 2. 使用 - ECB 模式加解密

需求

前端/后端使用 国密SM4 进行加密/解密,
【注意】前后端配合加解密时,需要我们自定义密钥 ,一般由后端提供

【方法1】 - 使用 sm4util 依赖

  1. 下载 sm4util 依赖

    npm install sm4util
    
  2. sm4util 依赖使用说明
    sm4util 依赖使用说明

  3. 使用 - 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 e
      if (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, t
  return (function r(e, t, n) {
    function o(i, a) {
      if (!t[i]) {
        if (!e[i]) {
          var u = typeof require == 'function' && require
          if (!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' && require
    for (var i = 0; i < n.length; i++) {
      o(n[i])
    }
    return o
  })(
    {
      '/': [
        function (r, e, t) {
          t.byteLength = c
          t.toByteArray = v
          t.fromByteArray = s
          var n = []
          var o = []
          var f = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
          var i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
          for (var a = 0, u = i.length; a < u; ++a) {
            n[a] = i[a]
            o[i.charCodeAt(a)] = a
          }
          o['-'.charCodeAt(0)] = 62
          o['_'.charCodeAt(0)] = 63
          function d(r) {
            var e = r.length
            if (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, a
            var u = r.length
            i = d(r)
            a = new f((u * 3) / 4 - i)
            t = i > 0 ? u - 4 : u
            var c = 0
            for (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) & 255
              a[c++] = (n >> 8) & 255
              a[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) & 255
                a[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 n
            var 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 e
            var t = r.length
            var o = t % 3
            var f = ''
            var i = []
            var a = 16383
            for (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 = 1
  this.isPadding = true
  this.sk = new Array(32)
}

function SM4() {
  this.SM4_ENCRYPT = 1
  this.SM4_DECRYPT = 0

  var 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 & n
    b[i] = t1 > 128 ? t1 - 256 : t1
    b[i + 1] = t2 > 128 ? t2 - 256 : t2
    b[i + 2] = t3 > 128 ? t3 - 256 : t3
    b[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 = 0
    var c = 0
    var 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 = 0
    var rk = 0
    var 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 & 0xff
    var 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_ENCRYPT
    this.sm4_setkey(ctx.sk, key)
  }

  this.sm4_setkey = function (SK, key) {
    var MK = new Array(4)
    var k = new Array(36)
    var i = 0
    MK[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 = null
    if (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 = 0
    var 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 = 0
    var length = input.length
    var 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 = bous
    if (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 = 0
    var length = input.length
    var bous = new Array()
    if (ctx.mode == this.SM4_ENCRYPT) {
      var k = 0
      for (; 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 = 0
      for (; 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 = bous
    if (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 = key
  this.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 = true
      ctx.mode = sm4.SM4_ENCRYPT
      var 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 = true
      ctx.mode = sm4.SM4_ENCRYPT

      var 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, c
    len = str.length
    for (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 = arr
    for (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].length
        var 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 模式加密

// 加密 - 使用默认秘钥 1111111111111111
var 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 e
      if (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, t
  return (function r(e, t, n) {
    function o(i, a) {
      if (!t[i]) {
        if (!e[i]) {
          var u = typeof require == 'function' && require
          if (!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' && require
    for (var i = 0; i < n.length; i++) {
      o(n[i])
    }
    return o
  })(
    {
      '/': [
        function (r, e, t) {
          t.byteLength = c
          t.toByteArray = v
          t.fromByteArray = s
          var n = []
          var o = []
          var f = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
          var i = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
          for (var a = 0, u = i.length; a < u; ++a) {
            n[a] = i[a]
            o[i.charCodeAt(a)] = a
          }
          o['-'.charCodeAt(0)] = 62
          o['_'.charCodeAt(0)] = 63

          function d(r) {
            var e = r.length
            if (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, a
            var u = r.length
            i = d(r)
            a = new f((u * 3) / 4 - i)
            t = i > 0 ? u - 4 : u
            var c = 0
            for (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) & 255
              a[c++] = (n >> 8) & 255
              a[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) & 255
                a[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 n
            var 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 e
            var t = r.length
            var o = t % 3
            var f = ''
            var i = []
            var a = 16383
            for (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 / 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
}

/**
 * utf8字符串转为字节数组
 * @param utf8Str
 * @returns {[]}
 */
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
}
/**
 * 字节数组转为utf8字符串
 * @param bytesArray
 * @returns {string}
 */
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('')))
}

/**
 * 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

  // Convert
  var 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 = 0
    var 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 = null
    if (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 = 16
    var loop = parseInt(data.length / blockLen) //注意不能整除会有小数,要取整
    var cipher = new Array((loop + 1) * blockLen)
    var tmp = new Array(blockLen)
    var oneCipher = null

    for (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 = 16
    var loop = data.length / blockLen - 1
    var tmp = new Array(blockLen)
    var onePlain = null
    var 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 = 16
    var loop = parseInt(data.length / blockLen) //注意不能整除会有小数,要取整
    var cipher = new Array((loop + 1) * blockLen)
    var tmp = new Array(blockLen)
    var oneCipher = null

    for (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 = 16
    var loop = data.length / blockLen
    var tmp = new Array(blockLen)
    var onePlain = null
    var 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 = len
  if (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

// 加密后传给后端进行解密

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】线性表之——“顺序表”

文章目录 前言顺序表主体结构顺序表操作函数介绍顺序表操作函数实现实现顺序&#xff1a;顺序表的初始化&#xff1a;顺序表插入函数&#xff1a;头插尾插指定位置插入 顺序表打印函数查找顺序表数据顺序表删除函数头删尾删指定位置删除 修改顺序表销毁顺序表 文件分类test.cSe…

webpack5搭建react框架-生产环境配置

webpack5配置react基础生产环境 一、前言 在项目构建时不同的环境下会有不同配置&#xff0c;在前面文章中已经使用webpack5配置好了基础环境和开发环境&#xff0c;但是在生产环境时有些配置和开发环境是不需要的&#xff0c;有些是可以在优化的&#xff0c;所以下面继续生产…

分支和循环语句——1

老铁们&#xff0c;这是博主初识C之后的第一篇C语言学习博客&#xff0c;希望可以给你们带来帮助。 文章目录 一、什么是语句? 二、分支语句 1、if语句 2、switch语句 三、while循环 一、什么是语句? C语句可分为以下五类&#xff1a; 1. 表达式语句 2. 函数调用语句…

模拟不同MIMO-OFDM方案的MATLAB代码(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果​ &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 MIMO技术指在发射端和接收端分别使用多个发射天线和接收天线&#xff0c;使信号通过发射端与接收端的多个天线传送和接收&…

杭州旭航集团,申请纳斯达克IPO上市,募资9800万美元

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;为中国企业提供数字内容营销服务的杭州旭航网络科技有限公司的控股公司Xuhang Holdings Ltd(以下简称&#xff1a;旭航集团)&#xff0c;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提…

随想录Day53--动态规划: 1143.最长公共子序列 ,1035.不相交的线 , 53. 最大子序和

1143.最长公共子序列,这题要画一个二维数组&#xff0c;用两层for循环来遍历每个字符&#xff0c;从而比较是否相等。用dp[i][j]来表示当遍历到text2的第i个字符和text1的第j个字符时&#xff0c;最长的公共子序列为多少。比如说两个字符串&#xff08;“abcde”和“ace”&…

怎么样成为一名Python工程师?到底要会哪些东西?你会了多少?

目录 重点&#xff1a;爬虫部分项目、源码展示python数据分析可视化大屏看板python爬虫爬取淘宝卤鸭货商品数据python游戏开发python自动化办公 重点&#xff1a; 1、做一名程序员&#xff0c;绝对要耐得住寂寞&#xff0c;并且要一直有点兴趣促进你学习。如果你完全没兴趣&am…

electron+vue3全家桶+vite项目搭建【十】vite路径取别名、多环境相关配置

文章目录 引入1.路径取别名配置2.测试别名配置3.环境变量配置4.验证环境变量配置 引入 我们之前写代码的时候用相对路径不是很方便&#xff0c;并且所有环境共用同一套配置也不太好&#xff0c;接下来我们通过vite配置一下路径别名和环境变量 视频讲解 vite官网 demo项目地址…

DIN论文翻译

摘要 在电子商务行业&#xff0c;利用丰富的历史行为数据更好地提取用户兴趣对于构建在线广告系统的点击率(CTR)预测模型至关重要。关于用户行为数据有两个关键观察结果&#xff1a;i) 多样性(diversity)。用户在访问电子商务网站时对不同种类的商品感兴趣。ii) 局部激活(local…

Linux驱动之GPIO函数、IO内存映射、混杂设备驱动

之前学习完了字符设备驱动的大体框架&#xff0c;现在我们就使用这个基本的框架来对硬件进行操作&#xff0c;例如通过指令控制led的状态&#xff0c;编写LED驱动。LED驱动有多种实现方式。 目录 GPIO函数 IO内存映射 混杂设备驱动 GPIO函数 首先加入需要的头文件。 #incl…

欧盟立法者签署公开信,近万人联名“暂停高级AI研发”

来源丨CoinTelegraph 编辑丨liuruiWeb3CN.Pro ChatGPT 曾经的势头有多猛烈如今就被行业大佬抵制的就有多严重。 近日&#xff0c;十几位欧盟 (EU) 政客签署了“暂停高级AI研发”的公开信&#xff0c;呼吁 AI &#xff08;人工智能&#xff09;的“安全”发展&#xff0c;特斯拉…

【Android -- 软技能】聊聊高效开发的一些套路与实践

前言 在开发中&#xff0c;编码我们有分层架构、设计模式做为套路来高效开发&#xff0c;但你也知道编码不是开发的全部&#xff0c;一个完全的开发流程用面向对象思想来概括&#xff0c;它分为OOA&#xff08;面向对象分析&#xff09;、OOD&#xff08;面向对象设计&#xf…

Flutter - 动画使用及自定义动画组件(tabbar跳动动画或文字抖动)

demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新&#xff0c;请前往github查看最新代码 Flutter - 动画组件&#xff08;tabbar跳动动画或文字抖动&#xff09; 序效果图动画简介动画类型Flutter动画的一些概念 常用动画实现隐式动画Tween动画Curve动画H…

低代码/无代码平台在软件开发中的应用

随着技术的不断发展&#xff0c;软件开发也在不断地进步。低代码/无代码平台已经成为软件开发的一个新的趋势。在这篇文章中&#xff0c;我们将深入探讨低代码/无代码平台在软件开发中的应用&#xff0c;包括它们的优势、如何选择合适的平台以及如何使用这些平台来开发高质量的…

机器学习 CarRentalData数据集分析和预测

介绍数据集 fuelType&#xff1a;燃料类型 rating&#xff1a;评级 renterTripsTaken&#xff1a;租房者出行 reviewCount&#xff1a;审阅计数 location.city&#xff1a;位置.城市 location.country&#xff1a;地点.国家/地区 location.latitude&#xff1a;位置.纬度 loca…

STM32按键实验中连接按键的GPIO管脚是上拉输入还是下拉输入

一、理解 关于STM32按键实验中连接按键的GPIO管脚是配置为上拉输入还是下拉输入的理解&#xff1a; 以江科大自动协教学视频按键输入实验为例&#xff1a; &#xff08;1&#xff09;按键KEY0<——>PE4 按键另一端接GND &#xff08;2&#xff09;按键KEY1<——&…

入门教学 | 快速了解集简云

集简云是一款超级软件连接器,无需开发,无需代码知识就可以轻松打通数百款软件之间的数据连接,构建自动化与智能化的业务流程。通过自动化业务流程,每月可节省企业数百甚至数万小时的人工成本。 集简云是什么? 集简云是一款超级软件连接器,无需开发,无需代码知识,就可以…

在现成的3D打印机上进行实验理论:一种数据孪生的攻击探测框架

在现成的3D打印机上提供了一种DT中攻击探测框架的DT解决方案的实验演示&#xff0c;作为说明性CPMS资源。通过网络安全DT对打印机正常运行、异常运行和攻击三种情况下的实验数据进行收集和分析&#xff0c;得出攻击检测结果。实验装置概述如下图所示。该实验研究是在现实世界设…

刚刚入职Android开发的应届生,该如何走向架构师

相信有不少从事Android开发的朋友&#xff0c;在工作一两年后会陷入一段迷茫期&#xff0c;有的是在工作中遇到了瓶颈&#xff0c;感觉无法突破&#xff1b;有的是想进阶成为架构师&#xff0c;但不知道如何进阶&#xff0c;因此产生了一些烦恼。为此小编在这里分享Android开发…

安卓开发: Compose 中的 Text 文本控件属性详解

Composable fun Text(text: String,modifier: Modifier Modifier,color: Color Color.Unspecified,fontSize: TextUnit TextUnit.Unspecified,fontStyle: FontStyle? null,fontWeight: FontWeight? null,fontFamily: FontFamily? null,letterSpacing: TextUnit TextU…