前端使用国密SM4进行加密、解密

news2024/11/22 9:15:09

目录

  • 需求
  • 【方法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/450534.html

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

相关文章

06期:使用 OPTIMIZER_TRACE 窥探 MySQL 索引选择的秘密

这里记录的是学习分享内容&#xff0c;文章维护在 Github&#xff1a;studeyang/leanrning-share。 优化查询语句的性能是 MySQL 数据库管理中的一个重要方面。在优化查询性能时&#xff0c;选择正确的索引对于减少查询的响应时间和提高系统性能至关重要。但是&#xff0c;如何…

scrapy框架爬取某壁纸网站美女壁纸 + MySQL持久化存储

文章目录 准备工作创建项目&#xff1a;设置&#xff08;settings&#xff09; 主程序入口meinv.py思路源代码 items 配置管道pipelines源代码 效果图总结 准备工作 创建项目&#xff1a; scraoy startproject bizhi cd bizhi scrapy genspider meinv bizhi360.com 设置&#…

ROS学习第二十九节——URDF之joint

此处留疑问&#xff0c;link,joint的origin子标签到底是怎么样的一种位置关系&#xff1f;&#xff1f;&#xff1f; https://download.csdn.net/download/qq_45685327/87717336 urdf 中的 joint 标签用于描述机器人关节的运动学和动力学属性&#xff0c;还可以指定关节运动的…

大数据-玩转数据-IDEA创建Maven工程

一、 IDEA集成Maven插件 打开IDEA&#xff0c;进入主界面后点击 file&#xff0c;然后点击 settings,在上面的快捷查找框中输入maven&#xff0c;查找与maven相关的设置&#xff0c;然后点击maven 修改maven的路径&#xff08;使用本地的Maven&#xff09;&#xff0c;以及修…

【流畅的Python学习笔记】2023.4.22

此栏目记录我学习《流畅的Python》一书的学习笔记&#xff0c;这是一个自用笔记&#xff0c;所以写的比较随意 元组 元组其实是对数据的记录&#xff1a;元组中的每个元素都存放了记录中一个字段的数据&#xff0c;外加这个字段的位置。简单试试元组的特性&#xff1a; char…

kong(1):Kong介绍

Kong是一款基于OpenResty&#xff08;Nginx Lua模块&#xff09;编写的高可用、易扩展的&#xff0c;由Mashape公司开源的API Gateway项目。Kong是基于NGINX和Apache Cassandra或PostgreSQL构建的&#xff0c;能提供易于使用的RESTful API来操作和配置API管理系统&#xff0c;…

复旦大学郁喆隽:网络制造出人的“幻象”,深度思考如何可能?

“人是什么?”这是亘古以来人们反复追问的一个古老命题。从元宇宙到ChatGPT&#xff0c;这个人人都在讨论、理解和实践互联网的时代&#xff0c;对“人”的自我定义和认知产生了哪些影响&#xff1f;    在3月12日复旦大学-华盛顿大学EMBA项目主办的“复调艺文沙龙”上&am…

计算长方形、三角形、圆形的面积和周长

系统设计框图&#xff1a; 图形模块的 概要设计&#xff08;设计数据结构和接口&#xff09;&#xff1a; 数据结构&#xff1a; float 表示面积和周长 长方形的数据&#xff08;一般typedef都是定义在对应模块的头文件中&#xff09; typedef struct{ float width; float he…

三菱GX Works2梯形图程序分段显示设置的具体方法示例

三菱GX Works2梯形图程序分段显示设置的具体方法示例 大家平时在使用GX Works2进行梯形图程序编辑时,默认是一整段在一起,程序步数较多时查看起来不是那么方便,下面就和大家分享如何通过声明编辑来实现程序分段显示。 具体方法可参考以下内容: 如下图所示,打开GX Works2编…

数据结构与算法(一):基础数据结构 算法概念、数组、链表、栈、队列

判断一个数是否是2的N次方&#xff1f; N & (N-1) 0 (N > 0)算题&#xff1a; 力扣 https://leetcode.cn/POJ http://poj.org/ 算法 算法概念 算法代表&#xff1a; 高效率和低存储 内存占用小、CPU占用小、运算速度快 算法的高效率与低存储&#xff1a;内存 C…

Oracle 定时任务job实际应用

Oracle 定时任务job实际应用 一、Oracle定时任务简介二、dbms_job涉及到的知识点三、初始化相关参数job_queue_processes四、实际创建一个定时任务&#xff08;一分钟执行一次&#xff09;&#xff0c;实现定时一分钟往表中插入数据4.1 创建需要定时插入数据的目标表4.2 创建定…

如何为Google Play的应用制作宣传视频

在用户打开我们的应用页面时&#xff0c;最先看到的是宣传视频&#xff0c;这是吸引潜在用户注意力的绝好机会&#xff0c;所以这对于 Google Play 来说是一件大事。 宣传视频和屏幕截图一起&#xff0c;都是引导用户去使用我们应用程序的第一步&#xff0c;能够让他们一打开应…

sibelius西贝柳斯2023中文版是什么打谱软件?如何下载

Sibelius是一款专业的音乐制谱软件&#xff0c;被广泛用于各类音乐创作、教育、表演等领域。通过Sibelius&#xff0c;用户可以快速、准确地制作各种类型的音乐谱面&#xff0c;同时支持多种音乐符号和效果的编辑、自定义和输出&#xff0c;可谓是音乐领域的必备工具之一。Sibe…

SQL Server tempdb 闩锁争用

当你反复创建和删除 TempDb 对象&#xff08;临时表、表变量等&#xff09;时&#xff0c;你可能会在 tempdb 中看到页面的闩锁争用。当你注意到tempdb 上的 PAGELATCH_* 争用&#xff08;sysprocesses 中的等待资源以 2: 开头&#xff09;时&#xff0c;请检查闩锁等待是否在 …

【语音之家】AI产业沙龙 —— 三星语言智能团队ICASSP2023论文分享会

由CCF语音对话与听觉专委会 、中国人工智能产业发展联盟&#xff08;AIIA&#xff09;评估组、三星电子中国研究院、语音之家、希尔贝壳共同主办的【语音之家】AI产业沙龙——三星语言智能团队ICASSP2023论文分享会&#xff0c;将于2023年4月25日18:30-20:20线上直播。 沙龙简介…

ERP系统有哪些功能模块?

一、ERP系统是什么 现在市面上的管理软件有很多&#xff0c;不少企业都会去选择一些操作简单便捷的软件&#xff0c;优化工作流程&#xff0c;提高工作效率&#xff0c;其中ERP系统就是常见的一种&#xff0c;ERP是企业资源计划(Enterprise Resource Planning)的简称&#xff…

深入了解Lock同步锁的优化

大家好&#xff0c;我是易安。 今天我们来简单谈谈在JDK1.5之后&#xff0c;Java提供的Lock同步锁。 相对于需要JVM隐式获取和释放锁的Synchronized同步锁&#xff0c;Lock同步锁&#xff08;以下简称Lock锁&#xff09;需要的是显示获取和释放锁&#xff0c;这就为获取和释放锁…

防止机械/移动硬盘休眠 - NoSleepHD

防止机械/移动硬盘休眠 - NoSleepHD 前言解决方案计算机硬盘移动硬盘 前言 机械硬盘休眠后唤醒需要一定时间&#xff0c;且频繁的启动和停止并不有利于硬盘的寿命&#xff0c;因此可根据自身需求防止机械硬盘休眠&#xff0c;下文以Win10系统为例介绍解决方案。 值得一提的是…

Java核心技术 卷1-总结-9

Java核心技术 卷1-总结-9 使用异常机制的技巧为什么要使用泛型程序设计定义简单泛型类泛型方法类型变量的限定 泛型类型的继承规则 使用异常机制的技巧 1.异常处理不能代替简单的测试。 使用异常的基本规则是&#xff1a;只在异常情况下使用异常机制。 2.不要过分地细化异常。…

第三章(3):深入理解Spacy库基本使用方法

第三章&#xff08;3&#xff09;&#xff1a;深入理解Spacy库基本使用方法 本章主要介绍了Spacy库的基本使用方法&#xff0c;包括安装、加载语言模型、分句、分词、词性标注、停用词识别、命名实体识别、依存分析和词性还原等内容。重点介绍了每个步骤的具体实现方式和应用场…