【无标题】

数据加密复合混用

AES加密算法和SM加密算法

AES
        高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥。
 发送方:明文通过密钥配合加密算法加密成密文;
 接收方:收到密文通过相同的密钥配合解密算法解密成明文

具体的加解密过程

SM
       国产国密算法有很多种,其中SM1、SM4、SM7、祖冲之密码(ZUC)是对称算法;SM2、SM9是非对称算法;SM3是哈希算法。
 这里简单解释一下sm2 和sm4两种,因为在后续的混合加解密过程中有使用到
 1、 SM2椭圆曲线公钥密码算法
SM2算法就是ECC椭圆曲线密码机制,但在签名、密钥交换方面不同于ECDSA、ECDH等国际标准,而是采取了更为安全的机制。另外,SM2推荐了一条256位的曲线作为标准曲线。
       SM2标准包括总则,数字签名算法,密钥交换协议,公钥加密算法四个部分,并在每个部分的附录详细说明了实现的相关细节及示例。
       SM2算法主要考虑素域Fp和F2m上的椭圆曲线,分别介绍了这两类域的表示,运算,以及域上的椭圆曲线的点的表示,运算和多倍点计算算法。然后介绍了编程语言中的数据转换,包括整数和字节串,字节串和比特串,域元素和比特串,域元素和整数,点和字节串之间的数据转换规则。
       //重点:sm2加密算法是非对称算法,加密与解密使用的密钥并不是同一个
       2 SM4对称算法
       该算法的分组长度为128比特,密钥长度为128比特。加密算法与密钥扩展算法都采用32轮非线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
       此算法采用非线性迭代结构,每次迭代由一个轮函数给出,其中轮函数由一个非线性变换和线性变换复合而成,非线性变换由S盒所给出。其中rki为轮密钥,合成置换T组成轮函数。轮密钥的产生与上图流程类似,由加密密钥作为输入生成,轮函数中的线性变换不同,还有些参数的区别。SM4算法的具体描述和示例见SM4标准。
       3 SM3杂凑算法
       SM3密码杂凑(哈希、散列)算法给出了杂凑函数算法的计算方法和计算步骤,并给出了运算示例。**此算法适用于商用密码应用中的数字签名和验证,消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。**在SM2,SM9标准中使用。
      此算法对输入长度小于2的64次方的比特消息,经过填充和迭代压缩,生成长度为256比特的杂凑值,其中使用了异或,模,模加,移位,与,或,非运算,由填充,迭代过程,消息扩展和压缩函数所构成。具体算法及运算示例见SM3标准。
对称加密算法

加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合。缺点是密钥的传输比较麻烦。

非对称加密算法

加密和解密用的密钥是不同的,这种加密方式是用数学上的难解问题构造的,通常加密解密的速度比较慢,适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal。

对SM国密加密的复合加密包装

从上面的文章钟我们了解到sm4对称加密是比较复合我们的业务场景的,政务领域也只能使用国密算法,但是考虑到安全性,密钥在传输过程中容易被拦截,导致密钥被窃取,从而影响数据安全,所以我们考虑使用更为安全复杂的sm2非对称加密算法,不过非对称算法解析过于缓慢也不符合我们的业务要求,否则容易造成接口缓慢请求超时,所以我们想到一个折中的方式,我们的数据加密使用sm4,但是我们传输sm4密钥的时候使用sm2对密钥进行加密,然后后台接收到我们的数据后先解密密钥,再用密钥解析数据,这样就算别人在传输过程中获取到了我们的密钥也无法使用,接下来就让我们实现吧

1、后台生成sm2的加密密钥

通过接口把生成的密钥发送到前台(sm2再生成密钥的时候会同时生成配套的一个加密密钥(公钥)一个解密密钥(私钥)):


if (this.$configApiUrl.VUE_APP_IS_ENCRYPT) {
      // 获取公钥用于秘钥加密
      this.$api.getpub.getpub().then(resp => {
        console.log(resp)
        const msg = rstr('this.form.userName') 
        localStorage.setItem('sec', msg)
        const sm2 = require('sm-crypto').sm2
        const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1
        const publicKey = resp // 公钥
        const encryptData = '04' + sm2.doEncrypt(msg, publicKey, cipherMode) // 加密结果
        setsm4(encryptData)
        this.unlogin()
      })
    } else {
      this.unlogin()
    }

2、前台随机获取sm4加密秘钥

前台在获取到sm2公钥的时候通过rstr()函数在前台生成sm4的密钥并加密存放到cookie里,然后前端自己保存一份sm4密钥到localStorage

// 随机获取sm4加密秘钥
export function rstr (name) {
  const sm3 = require('sm-crypto').sm3
  const $chars = sm3(Date.parse(new Date()) + name) // 杂凑
  const maxPos = $chars.length
  let str = ''
  for (let i = 0; i < 16; i++) {
    str += $chars.charAt(Math.floor(Math.random() * maxPos))
  }
  return str
}

rstr()里面使用sm3生成一串随机数再对传入参数进行随机编码生成sm4的密钥
接下来在我们发送请求的时候会把存放到cookie里的被加密过的sm4密钥存放到请求heade里面,如下:

const sm4 = getsm4()
   if (sm4) {
     config.headers.sec = getsm4() // 让每个请求携带自定义sm4
   }

后台在获取请求数据的时候会先获取heade里面的sec参数,然后使用之前生成的sm2私钥进行解密获取到sm4密钥,然后再使用这个密钥对数据进行解密,得到明文参数
注意:sm4加密的时候模式要和后端协商一致:mode


const SM4 = require('gm-crypt').sm4
      const sm4Config = {
        // 配置sm4参数
        key: localStorage.getItem('sec'), //
        mode: 'ecb', // 加密的方式有两种,ecb和cbc两种,也是看后端如何定义的,不过要是cbc的话下面还要加一个iv的参数,ecb不用
        cipherType: 'base64' //
      }


sm4的加密解密方法:


const sm4 = new SM4(sm4Config) //
const datas = sm4.decrypt(response.data.data) // 解密
const datas = sm4.encrypt(response.data.data) // 加密

在我们的工程里前端还有一个控制字段,判断是否加密


#是否加密的开关  //true => 加密  false => 不加密
VUE_APP_IS_ENCRYPT = false

解密判断写在axios文件夹index里面:
这里除了要判断是否打开加密开关还要把获取sm2公钥的接口放开,因为在调用这个接口的时候我们并没有做加密工作


// 加密开关
    const is_encrypt = vm.$configApiUrl?.VUE_APP_IS_ENCRYPT
    console.log('is_encrypt', is_encrypt)
    // 二进制下载处理
    if (response.config.responseType === 'blob' && response.status === 200) {
      return Promise.resolve(response)
    }
    const star = response.config.url.lastIndexOf('/')
    const end = response.config.url.length
    const urls = response.config.url.substring(star, end)
    if (urls === 'serverconfig.json') {
      return Promise.resolve(response.data)
    }
    if (urls !== '/getpub' && is_encrypt) {  //
   
   }else{
   
   }
   

加密判断写在axios文件夹function里面:只针对post接口进行加密,这里单独封装了方法存放在common公共方法里面

// sm4加密
export function sm4_encryption (params) {
  if (!new Vue().$configApiUrl.VUE_APP_IS_ENCRYPT) {
    return params
  }
  const SM4 = require('gm-crypt').sm4
  const sm4Config = {
    // 配置sm4参数
    key: localStorage.getItem('sec'), // 
    mode: 'ecb', // 加密的方式有两种,ecb和cbc两种,也是看后端如何定义的,不过要是cbc的话下面还要加一个iv的参数,ecb不用
    cipherType: 'base64' //
  }
  const sm4 = new SM4(sm4Config)// 这里new一个函数,将上面的sm4Config作为参数传递进去。然后就可以开心的加密了
  const Account = sm4.encrypt(JSON.stringify(params)) // 账号加密
  const data = {
    data: Account
  }
  return data
}

另外在url拼接参数里面有单独参数encrypt可以告知后台我们哪些接口需要单独不加密

encrypt=0表示前端不加密后端也不加密
encrypt=0表示前端不加密后端加密

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值