sm4加密实现请求头加密

前端实现方式1:此方法采用16位key可实现请求,也需使用方法2的md5Hex.js文件,最后需要将结果base64转换hex。
可参考的axios: 实际使用时还将再对少数细节做一下优化,比如requestPath参数,或一些方法封装。
测试函数执行耗时获取微秒级时间工具:

https://www.npmjs.com/package/microseconds

npm地址:https://www.npmjs.com/package/gm-crypt

const SM4 = require('gm-crypt').sm4
 import { md5 } from '@/util/md5Hex'

取秒时间戳:秒级

function timest() {
  var tmp = Date.parse(new Date()).toString();
  tmp = tmp.substr(0,10);
  // console.log(tmp, '123')
  return tmp;
}
base64转换hex的方法:
 function base64toHEX(base64) {
  var raw = atob(base64);
  var HEX = '';
  for (var i = 0; i < raw.length; i++ ) {
    var _hex = raw.charCodeAt(i).toString(16)
    HEX += (_hex.length==2?_hex:'0'+_hex);
  }
  return HEX.toUpperCase();
}

获取uuid:

function generateUUID() { var d = new Date().getTime();
if(window.performance && typeof window.performance.now ===
“function”){
d += performance.now(); //use high-precision timer if available } var uuid = ‘xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx’.replace(/[xy]/g,
function© {
var r = (d + Math.random()*16)%16 | 0;
d = Math.floor(d/16);
return (c==‘x’ ? r : (r&0x3|0x8)).toString(16); }); return uuid; }

请求头处理:

let deviceId = ''
          let requestTime = timest()
          let requestPath  = 'eduAuthTestPath' // 该路径暂时固定为测试接口路径,后续当替换为获取的需验证的具体接口
          let requestId = deviceId + '-' + requestTime + '-' + generateUUID()
          let requestContent =  encrypt(config.data, config.url)
          let content = requestId + requestTime + requestContent + requestPath
          console.log(content, 'smContent')
          let keyOne = md5(content, 32).toUpperCase()
          console.log(keyOne, '333')
          let smKey = md5('www.scedu.tech' + keyOne, 16).toUpperCase()
          // let smKey = md5('www.scedu.tech' + content, 32).toUpperCase()
          console.log(smKey, 'smKey')
          let sm4Config = {
            // encrypt/decypt main key; cannot be omitted
            key: smKey,
            // optional; can be 'cbc' or 'ecb'
            mode: 'ecb', // default
            // optional; when use cbc mode, it's necessary
            iv: null, // default is null
            // optional: this is the cipher data's type; Can be 'base64' or 'text'
            cipherType: 'base64' // default is base64
          }
          let sm4 = new SM4(sm4Config)
          // let encryptHex = SM4.encrypt(keyOne, smKey).toUpperCase()
          let encryptHex = base64toHEX(sm4.encrypt(keyOne)).toUpperCase()
          console.log(encryptHex, 'smEncryptHex')
          // let decryptHex = SM4.decrypt(encryptHex, smKey).toUpperCase()
          // console.log(decryptHex, 'decryptHex')
          let smObj = {
            requestTime: requestTime,
            requestId: requestId,
            auth: encryptHex,
            requestPath: requestPath,
          }
          config.headers["eduRequestAuth"] = JSON.stringify(smObj)
          config.data = {
            // data: encrypt(config.data, config.url)
            data: requestContent
          };

对接口response响应进行验证:

// 如果具有签名edurequestauth
     if (res.headers['edurequestauth']) {
      //  请求头
       const reqPath = getStore({ name: 'eduRequestAuth_contrast'})
       console.log(reqPath, 'reqPath')
      //  响应头
       let rspPath = JSON.parse(cloneDeep(res.headers['edurequestauth']))
       console.log(rspPath, 'rspPath');
      // console.log(md5(reqPath.requestId, 16))
      // console.log(cloneDeep(res.headers['edurequestauth']), JSON.stringify(reqPath))
      // console.log(timest(), 'ssss');
      let timeInterval = timest() - rspPath.responseTime
      console.log(timeInterval, 'timeInterval');
      let clientReqContent = ''
      if (status === 1000) {
        clientReqContent  = rspPath.requestId + rspPath.responseTime + res.data.result + rspPath.responsePath
      }
      if (md5(reqPath.requestId, 16) !== rspPath.responsePath) {
        // 验证requestId
        return {
          data : {
            status: 7001,
            msg: 'requestId不一致,可能存在欺诈行为。'
          }
        }
      } else if (timeInterval >= 20) {
        // 验证请求返回间隔时间
        return {
          data : {
            status: 7002,
            msg: '时间错误 请调节本地时间和网络一致。'
          }
        }
      } else if (clientReqContent && !decodeVerify(clientReqContent, rspPath.auth)) {
        // 验证结果是否和响应签名一致
        return {
          data : {
            status: 7003,
            msg: '验签失败 服务器返回内容不可信。'
          }
        }
      }
     }

解密验签方法:

// 解密验证
function decodeVerify(clientReqContent, auth) {
  let keyOne = md5(clientReqContent, 32).toUpperCase()
  console.log(keyOne, '333')
  let smKey = md5('www.scedu.tech' + keyOne, 16).toUpperCase()
  console.log(smKey, 'smKey')
  let sm4Config = {
    // encrypt/decypt main key; cannot be omitted
    key: smKey,
    // optional; can be 'cbc' or 'ecb'
    mode: 'ecb', // default
    // optional; when use cbc mode, it's necessary
    iv: null, // default is null
    // optional: this is the cipher data's type; Can be 'base64' or 'text'
    cipherType: 'base64' // default is base64
  }
  let sm4 = new SM4(sm4Config)
  let encryptHex = base64toHEX(sm4.encrypt(keyOne)).toUpperCase()
  console.log(encryptHex, 'authEncrypt');
  // console.log(encryptHex === auth, 'xxx');
  return encryptHex === auth;
}

前端实现方式 2:现阶段目前只发起了加密请求,但后端没有使用32位的密钥,故还未进行后续验证。
前端实现可直接参考npm文档或者git
但目前都采用32位md5加密才能准确还原。
npm 地址:

https://www.npmjs.com/package/gm-crypto

npm的圈红的这两个base64编码根据我们使用要求可以换成hex编码
在这里插入图片描述

java实现:
后端依赖:

org.bouncycastle
bcprov-jdk15on
1.62

注意: 以下代码位本地js引用,未使用npm包方式。如果使用npm包,则按npm文档的方式来使用。
本地sm4文件:
md5转换文件:

现阶段前端对请求头的加密,axios发起请求之前添加。deviceId 前端没有所以现在为空。
import SM4 from ‘@/util/smFour’
import { md5 } from ‘@/util/md5Hex’
let deviceId = ‘’
let requestTime = timest()
let requestPath = ‘eduAuthTestPath’ // 该路径暂时固定为测试接口路径,后续当替换为获取的需验证的具体接口

let requestId = deviceId + ‘-’ + requestTime + ‘-’ + generateUUID()
let requestContent = encrypt(config.data, config.url)
let content = requestId + requestTime + requestContent + requestPath
console.log(content, ‘smContent’)
let keyOne = md5(content, 32).toUpperCase()
console.log(keyOne, ‘333’)
// let smKey = md5(‘www.scedu.tech’ + keyOne, 16).toUpperCase()
let smKey = md5(‘www.scedu.tech’ + content, 32).toUpperCase()
console.log(smKey, ‘smKey’)
let encryptHex = SM4.encrypt(keyOne, smKey).toUpperCase()
console.log(encryptHex, ‘smEncryptHex’)
let decryptHex = SM4.decrypt(encryptHex, smKey).toUpperCase()
console.log(decryptHex, ‘decryptHex’)
let smObj = {
requestTime: requestTime,
requestId: requestId,
auth: encryptHex,
requestPath: requestPath,
}
config.headers[“eduRequestAuth”] = JSON.stringify(smObj)
config.data = {
data: requestContent
};

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值