前端 vue 、后端 python ,实现 RSA 分段加解密

一、项目框架

前端 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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端Vue传递加密密文到后端Java,后解密的示例代码如下: 前端Vue加密代码: ```javascript // 导入jsencrypt库 import JSEncrypt from 'jsencrypt' // 创建RSA加密实例 const encrypt = new JSEncrypt() // 设置RSA公钥 const publicKey = 'YOUR_RSA_PUBLIC_KEY' encrypt.setPublicKey(publicKey) // 要加密的数据 const data = 'YOUR_DATA_TO_ENCRYPT' // 使用RSA公钥进行加密 const encryptedData = encrypt.encrypt(data) // 将加密后的数据发送到后端 // 例如使用axios发送POST请求 axios.post('/api/decrypt', { encryptedData }) .then(response => { console.log(response.data) }) .catch(error => { console.error(error) }) ``` 后端Java解密代码: ```java import org.apache.commons.codec.binary.Base64; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.crypto.Cipher; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; @RestController public class DecryptionController { // 将Base64编码后的私钥字符串转换为PrivateKey对象 private PrivateKey getPrivateKey(String privateKeyStr) throws Exception { byte[] privateKeyBytes = Base64.decodeBase64(privateKeyStr); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(keySpec); } @PostMapping("/api/decrypt") public String decryptData(@RequestBody EncryptedData encryptedData) throws Exception { String privateKeyStr = "YOUR_RSA_PRIVATE_KEY"; PrivateKey privateKey = getPrivateKey(privateKeyStr); // 使用私钥进行解密 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] encryptedBytes = Base64.decodeBase64(encryptedData.getEncryptedData()); byte[] decryptedBytes = cipher.doFinal(encryptedBytes); // 返回解密后的数据 return new String(decryptedBytes, StandardCharsets.UTF_8); } } ``` 创建一个名为 `EncryptedData` 的Java类,用于接收前端传递的加密数据: ```java public class EncryptedData { private String encryptedData; public String getEncryptedData() { return encryptedData; } public void setEncryptedData(String encryptedData) { this.encryptedData = encryptedData; } } ``` 请将 `YOUR_RSA_PUBLIC_KEY` 替换为你的RSA公钥,将 `YOUR_RSA_PRIVATE_KEY` 替换为你的RSA私钥。在前端,你可以使用axios或其他HTTP库发送POST请求到后端的 `/api/decrypt` 路径,并将加密后的数据作为请求体的 `encryptedData` 字段传递。后端将解密后的数据作为响应返回给前端

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值