一、项目框架
前端 vue-element-admin (vue2) 框架,后端 flask (python3) 框架
二、前端实现 RSA 分段加解密
(参考自 https://blog.csdn.net/wxl1390/article/details/103495904 并根据项目实际情况进行调整)
1、安装依赖 jsencrypt
npm install jsencrypt
2、node_modules/jsencrypt/lib 下新建 JSEncryptRSAassist.js
/**
* RSA 分段解密辅助
* add by shengyinpeng 20231124
*/
// 16进制转byte数组
function hexToBytes(hex) {
let bytes = [];
for (let c = 0; c < hex.length; c += 2)
bytes.push(parseInt(hex.substr(c, 2), 16));
return bytes;
}
// byte数组转16进制
function bytesToHex(bytes) {
let hex = [];
for (let i = 0; i < bytes.length; i++) {
hex.push((bytes[i] >>> 4).toString(16));
hex.push((bytes[i] & 0xF).toString(16));
}
return hex.join("");
}
// base64转btye数组
function base64ToArrayBuffer(base64) {
let binary_string = window.atob(base64);
let len = binary_string.length;
let bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
}
// btye数组转base64
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
export {
hexToBytes,
bytesToHex,
base64ToArrayBuffer,
arrayBufferToBase64
}
3、修改 node_modules/jsencrypt/lib/JSEncrypt.js
import {hexToBytes, bytesToHex, base64ToArrayBuffer, arrayBufferToBase64} from "./JSEncryptRSAassist.js";
...
// 在 JSEncrypt 方法最下面新增
/**
* 分段加密
* add by shengyinpeng
* 参考自 https://blog.csdn.net/wxl1390/article/details/103495904
* @param string
* @returns {string|boolean}
*/
JSEncrypt.prototype.encryptLong = function (string) {
let k = this.getKey();
try {
let ct = ""; // RSA每次加密最大117bytes,需要辅助方法判断字符串截取位置
// 1.获取字符串截取点
let bytes = new Array();
bytes.push(0);
let byteNo = 0;
let len, c;
len = string.length;
let temp = 0;
for (let 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 (let i = 0; i < bytes.length - 1; i++) {
let str;
if (i == 0) {
str = string.substring(0, bytes[i + 1] + 1);
} else {
str = string.substring(bytes[i] + 1, bytes[i + 1] + 1);
}
let t1 = k.encrypt(str);
ct += t1;
};
if (bytes[bytes.length - 1] != string.length - 1) {
let lastStr = string.substring(bytes[bytes.length - 1] + 1);
ct += k.encrypt(lastStr);
}
return hexToBytes(ct);
}
let t = k.encrypt(string);
let y = hexToBytes(t);
return y;
} catch (ex) {
return false;
}
};
/**
* 分段解密
* add by shengyinpeng
* 参考自 https://blog.csdn.net/wxl1390/article/details/103495904
* @param string
* @returns {string|boolean}
*/
JSEncrypt.prototype.decryptLong = function (string) {
let k = this.getKey();
const MAX_DECRYPT_BLOCK = 128; // 分段解密最大长度限制为128字节
try {
let ct = "";
let t1;
let bufTmp;
let hexTmp;
let str = bytesToHex(string); // 这块可能有些没有必要,因为sting参数已经及转为byte数组
let buf = hexToBytes(str);
let inputLen = buf.length;
let offSet = 0; // 开始长度
let 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;
} else {
bufTmp = buf.slice(offSet, inputLen);
hexTmp = bytesToHex(bufTmp);
t1 = k.decrypt(hexTmp);
ct += t1;
}
offSet += MAX_DECRYPT_BLOCK;
endOffSet += MAX_DECRYPT_BLOCK;
}
return ct;
} catch (ex) {
return false;
}
};
/**
* base64转btye数组
* add by shengyinpeng
*/
JSEncrypt.prototype.base64ToArrayBuffer = function (base64) {
return base64ToArrayBuffer(base64);
};
/**
* btye数组转base64
* add by shengyinpeng
*/
JSEncrypt.prototype.arrayBufferToBase64 = function (buffer) {
return arrayBufferToBase64(buffer);
};
4、src/utils目录下新建加解密封装 js 文件
import JSEncrypt from 'jsencrypt'
import { Base64 } from 'js-base64'
// 请求服务端信息加密
// 1、将原文进行base64 encode
// 2、RSA加密
// 3、将密文进行base64 encode(由于步骤3的方法返回的密文已经是经过base64 encode的,故此步骤省略)
export function encryptReqData(msg) {
return rsaEncrypt(Base64.encode(msg))
}
// 服务端返回信息解密
// 1、进行base64 decode获取密文(由于步骤二的方法会先一步把入参进行base64 decode,故此步骤省略)
// 2、RSA解密
// 3、进行base64 decode获取原文
export function decryptRespData(msg) {
return Base64.decode(rsaDecrypt(msg))
}
// RSA加密
// 要用服务端的公钥进行加密(这里用到分段加密,参考:https://blog.csdn.net/wxl1390/article/details/103495904)
// 返回的密文是经过base64 encode的
function rsaEncrypt(data) {
const JsEncrypt = new JSEncrypt()
const pubKey = process.env.VUE_APP_SERVICE_RSA_PUB_KEY
JsEncrypt.setPublicKey(pubKey)
return JsEncrypt.arrayBufferToBase64(JsEncrypt.encryptLong(data.toString()))
}
// RSA解密
// 要用前端的私钥进行解密(这里用到分段解密,参考:https://blog.csdn.net/wxl1390/article/details/103495904)
// 会先把入参进行base64 decode
function rsaDecrypt(data) {
const JsEncrypt = new JSEncrypt()
const priKey = process.env.VUE_APP_FRONT_RSA_PRI_KEY
JsEncrypt.setPrivateKey(priKey)
return JsEncrypt.decryptLong(JsEncrypt.base64ToArrayBuffer(data.toString()))
}
5、引用示例
由于我是把 RSA 加解密用在前后端请求交互上,故对 src/utils/request.js 进行修改
import { encryptReqData, decryptRespData } from '@/utils/encryption-decryption'
...
// 在请求拦截器下
// 加密请求体
const req = JSON.stringify(config.data)
config.data = encryptReqData(req)
...
// 在响应拦截器下
// 解密响应体
const enc_res = response.data
const res = JSON.parse(decryptRespData(enc_res))
三、后端实现 RSA 分段加解密
1、安装依赖 pycryptodome
pip install pycryptodome
2、新建加解密封装 py 文件
import base64
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto.PublicKey import RSA
encoding = "utf-8"
def get_key(key_or_path):
if "BEGIN PUBLIC KEY" in key_or_path or "BEGIN PRIVATE KEY" in key_or_path:
pem_data = key_or_path
else:
with open(key_or_path) as f:
pem_data = f.read()
return RSA.importKey(pem_data)
def rsa_encrypt(msg, pub_path, max_length=100):
"""
RSA加密
:param msg: 加密字符串
:param pub_path: 公钥路径
:param max_length: 1024bit的秘钥不能超过117, 2048bit的秘钥不能超过245
:return:
"""
# 1、将原文进行base64 encode
b64_data = base64.b64encode(msg.encode(encoding)).decode(encoding)
# 2、RSA加密
key = get_key(pub_path)
cipher = PKCS1_cipher.new(key)
res_byte = bytes()
for i in range(0, len(b64_data), max_length):
res_byte += cipher.encrypt(b64_data[i:i + max_length].encode(encoding))
# 3、将密文进行base64 encode
return base64.b64encode(res_byte).decode(encoding)
def rsa_decrypt(msg, pri_path, max_length=128):
"""
RSA解密
:param msg: 加密字符串
:param pri_path: 私钥路径
:param max_length: 1024bit的秘钥用128,2048bit的秘钥用256位
:return:
"""
# 1、进行base64 decode获取密文
data = base64.b64decode(msg)
# 2、RSA解密
key = get_key(pri_path)
cipher = PKCS1_cipher.new(key)
res_bytes = bytes()
for i in range(0, len(data), max_length):
res_bytes += cipher.decrypt(data[i:i + max_length], 0)
# 3、进行base64 decode获取原文
return base64.b64decode(res_bytes.decode(encoding)).decode(encoding)