非对称加密RSA

395 阅读2分钟

非对称加密RSA

 RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)

加密解密流程

公钥加密,私钥解密

私钥签名,公钥验签

使用场景

前后端约定要对一个接口的传参 进行加密解密,

RSA加密

  1. 后端生成一对密钥,将公钥传给前端,私钥自己保留
  2. 前端传参的时候用公钥加密
  3. 后端拿到参数后用私钥解密

在这个过程中,只有2次传递过程,第一次是后端传递公钥给前端,第二次是前端传递加密消息给后端,即使都被敌方截获,也没有危险性,因为只有后端的私钥才能对消息进行解密,防止了消息内容的泄露。

RSA 签名

  1. 前端生成一对密钥,将公钥传给后端,私钥自己保留
  2. 前端用自己的私钥对消息加签,形成签名,并将加签的消息和消息本身一起传递给后端
  3. 后端收到消息后,在获取前端的公钥进行验签,如果验签出来的内容与消息本身一致,证明消息是前端回复的。

在这个过程中,只有2次传递过程,第一次是前端传递加签的消息和消息本身给后端,第二次是后端获取前端的公钥,即使都被敌方截获,也没有危险性,因为只有前端的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带签名的回复给后端,防止了消息内容的篡改。

前端代码具体实现流程

这里仅展示 RSA 加密的使用场景 前端技术使用的是 angular

引入jsencrypt插件

 npm install --save jsencrypt

jsencrypt官网链接 travistidwell.com/jsencrypt/

对参数加密

 import {JSEncrypt} from 'jsencrypt';
async arSoftToken(deviceId, status, requestId, verifyToken) {
      let publicKey = await this.storageService.get('public_key');

      let encrypt = new JSEncrypt();
      encrypt.setPublicKey(publicKey);
      const encryptParam = encrypt.encrypt(JSON.stringify({
        requestId:requestId,
        verifyToken:verifyToken
      }).trim()); 
    
      return new Promise((resolve, reject) => {
        this.nativeHttp.put(`${environment.bffApi}/user/softToken`, 
        { deviceId:deviceId,
          status:status,
          encryptToken:encryptParam
        }, {}).then(
     
        );
      });
    }

解密

const decrypt = new JSEncrypt();
decrypt.setPrivateKey(this.key);       
const decrypted = decrypt.decrypt(param);
                                                               

生成RSA键值对

export const getRsaKeys = () => {
  return new Promise( (resolve, reject) => {
    window.crypto.subtle
    .generateKey(
      {
        name: 'RSA-OAEP',
        modulusLength: 2048, //can be 1024, 2048, or 4096
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
        hash: { name: 'SHA-512' }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
      },
      true, //whether the key is extractable (i.e. can be used in exportKey)
      ['encrypt', 'decrypt'] //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
    )
    .then(function (key) {
      window.crypto.subtle
        .exportKey('pkcs8', key.privateKey)
        .then(function (keydata1) {
          window.crypto.subtle
            .exportKey('spki', key.publicKey)
            .then(function (keydata2) {
              var privateKey = RSA2text(keydata1, 1);
              var publicKey = RSA2text(keydata2);
              resolve({privateKey, publicKey});
            });
        })
    })
  })
  
}

const RSA2text = (buffer, isPrivate = 0) => {
  var binary = '';
  var bytes = new Uint8Array(buffer);
  var len = bytes.byteLength;
  for (var i = 0; i < len; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  var base64 = window.btoa(binary);
  var text = '-----BEGIN ' + (isPrivate ? 'PRIVATE' : 'PUBLIC') + ' KEY-----\n';
  text += base64
    .replace(/[^\x00-\xff]/g, '$&\x01')
    .replace(/.{64}\x01?/g, '$&\n');
  text += '\n-----END ' + (isPrivate ? 'PRIVATE' : 'PUBLIC') + ' KEY-----';
  return text;
}

更多相关用法

github.com/lop3ziv4n/a…