Vue項目 RSA分段加解密

一、引入JSEncrypt

1.安裝依賴

npm install jsencrypt

2.在main.js(需要引入的地方)引入

import { JSEncrypt } from 'jsencrypt'

3.前端公鑰加密、後臺私鑰解密、請求來的數據後臺公鑰加密、前端私鑰解密

二、引入轉碼方法

 // 16進制轉byte數組

function hexToBytes(hex) {
  for (var bytes = [], c = 0; c < hex.length; c += 2)
    bytes.push(parseInt(hex.substr(c, 2), 16));
  return bytes; 
}

// byte數組轉16進制

function bytesToHex(bytes) {
  for (var hex = [], i = 0; i < bytes.length; i++) {
    hex.push((bytes[i] >>> 4).toString(16));
    hex.push((bytes[i] & 0xF).toString(16));
  }
  return hex.join("");
};

在原有的JSEncrypt中添加分段加解密的方法

分段加密

JSEncrypt.prototype.encryptLong2 = function (string) {

  var k = this.getKey(); 

  try {

    var ct = "";     //RSA每次加密最大117bytes,需要輔助方法判斷字符串截取位置

    //1.獲取字符串截取點

    var bytes = new Array();

    bytes.push(0);

    var byteNo = 0;

    var len, c;

    len = string.length;

    var temp = 0;

    for (var i = 0; i < len; i++) {

      c = string.charCodeAt(i);

      if (c >= 0x010000 && c <= 0x10FFFF) {

        byteNo += 4;

      } else if (c >= 0x000800 && c <= 0x00FFFF) {

        byteNo += 3;

      } else if (c >= 0x000080 && c <= 0x0007FF) {

        byteNo += 2;

      } else {

        byteNo += 1;

      }

      if ((byteNo % 117) >= 114 || (byteNo % 117) == 0) {

        if (byteNo - temp >= 114) {

          bytes.push(i);

          temp = byteNo;

        }

      }

    }

    //2.截取字符串並分段加密

    if (bytes.length > 1) {

      for (var i = 0; i < bytes.length - 1; i++) {

        var str;

        if (i == 0) {

          str = string.substring(0, bytes[i + 1] + 1);

        } else {

          str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);

        }

        var t1 = k.encrypt(str);

        ct += t1;

      };

      if (bytes[bytes.length - 1] != string.length - 1) {

        var lastStr = string.substring(bytes[bytes.length - 1] + 1);

        ct += k.encrypt(lastStr);

      }

      return hexToBytes(ct);

    }

    var t = k.encrypt(string);

    var y = hexToBytes(t);

    return y;

  } catch (ex) {

    return false;

  }

};

// utf-8數組轉字符串

function utf8ByteToUnicodeStr(utf8Bytes) {

  var unicodeStr = "";

  for (var pos = 0; pos < utf8Bytes.length;) {

    var flag = utf8Bytes[pos];

    var unicode = 0;

    if ((flag >>> 7) === 0) {

      unicodeStr += String.fromCharCode(utf8Bytes[pos]);

      pos += 1;

    } else if ((flag & 0xFC) === 0xFC) {

      unicode = (utf8Bytes[pos] & 0x3) << 30;

      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 24;

      unicode |= (utf8Bytes[pos + 2] & 0x3F) << 18;

      unicode |= (utf8Bytes[pos + 3] & 0x3F) << 12;

      unicode |= (utf8Bytes[pos + 4] & 0x3F) << 6;

      unicode |= (utf8Bytes[pos + 5] & 0x3F);

      unicodeStr += String.fromCharCode(unicode);

      pos += 6;

    } else if ((flag & 0xF8) === 0xF8) {

      unicode = (utf8Bytes[pos] & 0x7) << 24;

      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 18;

      unicode |= (utf8Bytes[pos + 2] & 0x3F) << 12;

      unicode |= (utf8Bytes[pos + 3] & 0x3F) << 6;

      unicode |= (utf8Bytes[pos + 4] & 0x3F);

      unicodeStr += String.fromCharCode(unicode);

      pos += 5;

    } else if ((flag & 0xF0) === 0xF0) {

      unicode = (utf8Bytes[pos] & 0xF) << 18;

      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 12;

      unicode |= (utf8Bytes[pos + 2] & 0x3F) << 6;

      unicode |= (utf8Bytes[pos + 3] & 0x3F);

      unicodeStr += String.fromCharCode(unicode);

      pos += 4;

    } else if ((flag & 0xE0) === 0xE0) {

      unicode = (utf8Bytes[pos] & 0x1F) << 12;;

      unicode |= (utf8Bytes[pos + 1] & 0x3F) << 6;

      unicode |= (utf8Bytes[pos + 2] & 0x3F);

      unicodeStr += String.fromCharCode(unicode);

      pos += 3;

    } else if ((flag & 0xC0) === 0xC0) { //110

      unicode = (utf8Bytes[pos] & 0x3F) << 6;

      unicode |= (utf8Bytes[pos + 1] & 0x3F);

      unicodeStr += String.fromCharCode(unicode);

      pos += 2;

    } else {

      unicodeStr += String.fromCharCode(utf8Bytes[pos]);

      pos += 1;

    }

  }

  return unicodeStr;

}

分段解密

JSEncrypt.prototype.decryptLong2 = function (string) {

  var k = this.getKey();

  var MAX_DECRYPT_BLOCK = 128;//分段解密最大長度限制爲128字節

  try {

    var ct = "";

    var t1;

    var bufTmp;

    var hexTmp;

    var str = bytesToHex(string); //這塊可能有些沒有必要,因爲sting參數已經及轉爲byte數組

    var buf = hexToBytes(str);

    var inputLen = buf.length;

    //開始長度

    var offSet = 0;

    //結束長度

    var endOffSet = MAX_DECRYPT_BLOCK;

    //分段解密

    while (inputLen - offSet > 0) {

      if (inputLen - offSet > MAX_DECRYPT_BLOCK) {

        bufTmp = buf.slice(offSet, endOffSet);

        hexTmp = bytesToHex(bufTmp);

        t1 = k.decrypt(hexTmp);

        ct += t1;

        console.log('分段' + offSet)

        console.log(hexTmp)

        console.log(t1)

      } else {

        bufTmp = buf.slice(offSet, inputLen);

        hexTmp = bytesToHex(bufTmp);

        t1 = k.decrypt(hexTmp);

        ct += t1;

        console.log('分段' + offSet)

        console.log(hexTmp)

        console.log(t1)

      }

      offSet += MAX_DECRYPT_BLOCK;

      endOffSet += MAX_DECRYPT_BLOCK;

    }

    return ct;

  } catch (ex) {

    return false;

  }

};

三、使用方法

前端給後臺傳輸所以要把byte數組進行base64編碼
後臺傳輸來的base64的數據前端解碼爲byte數組

// btye數組轉base64
function arrayBufferToBase64(buffer) {

  var binary = '';

  var bytes = new Uint8Array(buffer);

  var len = bytes.byteLength;

  for (var i = 0; i < len; i++) {

    binary += String.fromCharCode(bytes[i]);

  }

  return window.btoa(binary);

}

// base64轉btye數組
function base64ToArrayBuffer(base64) {

  var binary_string = window.atob(base64);

  var len = binary_string.length;

  var bytes = new Uint8Array(len);

  for (var i = 0; i < len; i++) {

    bytes[i] = binary_string.charCodeAt(i);

  }

  return bytes;

}

使用加密方法

const $getrsa = function (password) {

  let encrypt = new JSEncrypt()

  encrypt.setPublicKey('-----BEGIN PUBLIC KEY-----公鑰----END PUBLIC KEY-----') // 公鑰

  let getrsadata = arrayBufferToBase64(encrypt.encryptLong2(password)); //將加密的數據轉碼爲base64

  return getrsadata //加密後的數據

}

使用解密方法

const $decrsa = function (passwords) {

  let encrypt = new JSEncrypt()

  encrypt.setPrivateKey('-----BEGIN PRIVATE KEY-----私鑰-----') // 私鑰

  let decrsadata = encrypt.decryptLong2(base64ToArrayBuffer(passwords)) // password要解密的數據 先轉爲byte數組在進行解碼

  return decrsadata //解密後的數據

}

四、Tip

後臺如果進行分段加密請嚴格使用117字節劃分,前端解析請嚴格使用128字節劃分。

鏈接:https://www.jianshu.com/p/70dc1b5e2a7c

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章