jsencrypt公鑰分段加密,支持后端解密

前端使用jsencryp實現分段加密。
解決長文本RSA加密報錯問題。
支持文本包含中文。
支持后端解密。

前端加密代碼:

// import { JSEncrypt } from 'jsencrypt'
const JSEncrypt = require('jsencrypt')
/*** 使用 JSEncrypt 實現分段 RSA 加密(正確處理中文字符)* @param {string} data - 要加密的數據* @param {string} publicKey - PEM格式的公鑰* @returns {string} 加密后的數據(Base64編碼)*/
function encryptWithJSEncrypt(data, publicKey) {const encrypt = new JSEncrypt();encrypt.setPublicKey(publicKey);// RSA 2048位密鑰時,最大加密明文長度為245字節const MAX_ENCRYPT_BLOCK = 245;const encryptedBytes = [];// 按字符安全地分段,避免切斷UTF-8字符let startIndex = 0;while (startIndex < data.length) {// 嘗試獲取一段文本,確保其UTF-8編碼后的字節長度不超過MAX_ENCRYPT_BLOCKlet endIndex = startIndex;let segment = '';// 逐個添加字符,直到接近最大長度限制while (endIndex < data.length) {const nextSegment = segment + data.charAt(endIndex);const nextSegmentBytes = new TextEncoder().encode(nextSegment);// 如果添加下一個字符會超出限制,則停止if (nextSegmentBytes.length > MAX_ENCRYPT_BLOCK) {break;}segment = nextSegment;endIndex++;}// 如果沒有成功獲取到任何字符(理論上不應該發生),則至少獲取一個字符if (segment.length === 0 && startIndex < data.length) {segment = data.charAt(startIndex);endIndex = startIndex + 1;}// 加密當前段const encryptedBlock = encrypt.encrypt(segment);if (!encryptedBlock) {throw new Error('加密失敗');}// 將加密后的Base64字符串轉換為字節數組const encryptedBlockBytes = atob(encryptedBlock);for (let j = 0; j < encryptedBlockBytes.length; j++) {encryptedBytes.push(encryptedBlockBytes.charCodeAt(j));}// 移動到下一段startIndex = endIndex;}// 將所有加密后的字節數據進行Base64編碼let result = '';for (let i = 0; i < encryptedBytes.length; i++) {result += String.fromCharCode(encryptedBytes[i]);}return btoa(result);
}// 帶不帶-----BEGIN PUBLIC KEY-----均可
let pubkey = '-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCKy+dsq0bbBhdt2Z2UDirtemU/7lAb746JngP4KLDmH9IgLZfranlflVLjfDW6BMYEVP3mN0HPlW4RWMPORgaHUu1yECzWqQX2bpDlN+IAZZhytTlMEyA+3DqKy3tS3QlIheDpMj7T6rOrfVFUDu3A4Tg/I3xqkToAHWI3rW3O3kDcFkFWVKYLiHsBhCd6LtauYENsB36voQKMGDrd9KZd5ndcy7otAU/+ITEfIMyKoD0eCojuDVOtREVY9jaos6kMDAtm8+ppbC7/0Q4TBf1zWaC1xDI6sTp+L6sYD6fDE2ni1/ly718hvHdPYC6GanmrME51pGGp8FgIkYpWXiQIDAQAB-----END PUBLIC KEY-----'let longText = "這是一段需要加密的長文本示例。RSA加密算法對加密的數據長度有限制,使用分段加密可以解決這個問題。當文本長度超過密鑰所能處理的最大長度時,我們需要將文本分成多個部分分別進行加密。Java后端使用的RSA/ECB/PKCS1Padding模式與JSEncrypt默認模式兼容"
let encrypt= encryptWithJSEncrypt(longText, pubkey)
console.log(encrypt)

后端工具類:

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;public class RSAUtils {private static final String ALGORITHM = "RSA";private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";private static final int KEY_SIZE = 2048;// RSA最大加密明文大小private static final int MAX_ENCRYPT_BLOCK = 245;// RSA最大解密密文大小private static final int MAX_DECRYPT_BLOCK = 256;/*** 生成RSA密鑰對** @return KeyPair對象包含公鑰和私鑰*/public static KeyPair generateKeyPair() throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);keyPairGenerator.initialize(KEY_SIZE);return keyPairGenerator.generateKeyPair();}/*** 使用公鑰加密數據(支持分段加密)** @param data 要加密的數據* @param publicKey 公鑰* @return 加密后的數據(Base64編碼)*/public static String encrypt(String data, PublicKey publicKey) throws Exception {Cipher cipher = Cipher.getInstance(TRANSFORMATION);cipher.init(Cipher.ENCRYPT_MODE, publicKey);byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);int inputLen = dataBytes.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 對數據分段加密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return Base64.getEncoder().encodeToString(encryptedData);}/*** 使用私鑰解密數據(支持分段解密)** @param encryptedData 加密的數據(Base64編碼)* @param privateKey 私鑰* @return 解密后的原始數據*/public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {Cipher cipher = Cipher.getInstance(TRANSFORMATION);cipher.init(Cipher.DECRYPT_MODE, privateKey);byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);int inputLen = encryptedBytes.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;byte[] cache;int i = 0;// 對數據分段解密while (inputLen - offSet > 0) {if (inputLen - offSet > MAX_DECRYPT_BLOCK) {cache = cipher.doFinal(encryptedBytes, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedBytes, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return new String(decryptedData, StandardCharsets.UTF_8);}/*** 從字符串加載公鑰** @param publicKey 公鑰字符串* @return PublicKey對象*/public static PublicKey loadPublicKey(String publicKey) throws Exception {byte[] keyBytes = Base64.getDecoder().decode(publicKey);X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);return keyFactory.generatePublic(spec);}/*** 從字符串加載私鑰** @param privateKey 私鑰字符串* @return PrivateKey對象*/public static PrivateKey loadPrivateKey(String privateKey) throws Exception {byte[] keyBytes = Base64.getDecoder().decode(privateKey);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);return keyFactory.generatePrivate(spec);}/*** 將公鑰轉換為字符串** @param publicKey 公鑰* @return Base64編碼的公鑰字符串*/public static String publicKeyToString(PublicKey publicKey) {return Base64.getEncoder().encodeToString(publicKey.getEncoded());}/*** 將私鑰轉換為字符串** @param privateKey 私鑰* @return Base64編碼的私鑰字符串*/public static String privateKeyToString(PrivateKey privateKey) {return Base64.getEncoder().encodeToString(privateKey.getEncoded());}/*** 測試加密解密功能*/public static void main(String[] args) {try {// 生成密鑰對KeyPair keyPair = generateKeyPair();PublicKey publicKey = keyPair.getPublic();PrivateKey privateKey = keyPair.getPrivate();// 打印公鑰和私鑰System.out.println("公鑰: " + publicKeyToString(publicKey));System.out.println("私鑰: " + privateKeyToString(privateKey));// 測試數據String testData = "這是一段需要加密的長文本示例。RSA加密算法對加密的數據長度有限制,使用分段加密可以解決這個問題。當文本長度超過密鑰所能處理的最大長度時,我們需要將文本分成多個部分分別進行加密。Java后端使用的RSA/ECB/PKCS1Padding模式與JSEncrypt默認模式兼容";// 加密String encryptedData = encrypt(testData, publicKey);System.out.println("加密后數據: " + encryptedData);// 解密String decryptedData = decrypt(encryptedData, privateKey);System.out.println("解密后數據: " + decryptedData);// 驗證System.out.println("加密解密是否成功: " + testData.equals(decryptedData));} catch (Exception e) {e.printStackTrace();}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/97928.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/97928.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/97928.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

生成一份關于電腦電池使用情況、健康狀況和壽命估算的詳細 HTML 報告

核心作用 powercfg /batteryreport 是一個在 Windows 命令提示符或 PowerShell 中運行的命令。它的核心作用是&#xff1a;生成一份關于電腦電池使用情況、健康狀況和壽命估算的詳細 HTML 報告。 這份報告非常有用&#xff0c;特別是對于筆記本電腦用戶&#xff0c;它可以幫你&…

從 0 到 1 實現 PyTorch 食物圖像分類:核心知識點與完整實

食物圖像分類是計算機視覺的經典任務之一&#xff0c;其核心是讓機器 “看懂” 圖像中的食物類別。隨著深度學習的發展&#xff0c;卷積神經網絡&#xff08;CNN&#xff09;憑借強大的特征提取能力&#xff0c;成為圖像分類的主流方案。本文將基于 PyTorch 框架&#xff0c;從…

Python 值傳遞 (Pass by Value) 和引用傳遞 (Pass by Reference)

Python 值傳遞 {Pass by Value} 和引用傳遞 {Pass by Reference}1. Mutable Objects and Immutable Objects in Python (Python 可變對象和不可變對象)2. Pass by Value and Pass by Reference2.1. What is Pass by Value in Python?2.2. What is Pass by Reference in Python…

aippt自動生成工具有哪些?一文看懂,總有一款適合你!

在當今快節奏的工作與學習環境中&#xff0c;傳統耗時的PPT制作方式已難以滿足高效表達的需求。隨著人工智能技術的發展&#xff0c;AI自動生成PPT工具應運而生&#xff0c;成為提升演示文稿制作效率的利器。這類工具通過自然語言處理和深度學習技術&#xff0c;能夠根據用戶輸…

Langflow 框架中 Prompt 技術底層實現分析

Langflow 框架中 Prompt 技術底層實現分析 1. Prompt 技術概述 Langflow 是一個基于 LangChain 的可視化 AI 工作流構建框架&#xff0c;其 Prompt 技術是整個系統的核心組件之一。Prompt 技術主要負責&#xff1a; 模板化處理&#xff1a;支持動態變量替換的提示詞模板變量驗證…

前端、node跨域問題

前端頁面訪問node后端接口跨域報錯 Access to XMLHttpRequest at http://192.18.31.75/api/get?namess&age19 from origin http://127.0.0.1:5500 has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource. 這個報…

超越馬力歐:如何為經典2D平臺游戲注入全新靈魂

在游戲開發的世界里&#xff0c;2D平臺游戲仿佛是一位熟悉的老朋友。從《超級馬力歐兄弟》開啟的黃金時代到現在&#xff0c;這個類型已經經歷了數十年的演變與打磨。當每個基礎設計似乎都已被探索殆盡時&#xff0c;我們如何才能打造出一款令人耳目一新的平臺游戲&#xff1f;…

基于Springboot + vue3實現的時尚美妝電商網站

項目描述本系統包含管理員和用戶兩個角色。管理員角色&#xff1a;商品分類管理&#xff1a;新增、查看、修改、刪除商品分類。商品信息管理&#xff1a;新增、查看、修改、刪除、查看評論商品信息。用戶管理&#xff1a;新增、查看、修改、刪除用戶。管理員管理&#xff1a;查…

網絡協議之https?

寫在前面 https協議還是挺復雜的&#xff0c;本人也是經過了很多次的學習&#xff0c;依然感覺一知半解&#xff0c;無法將所有的知識點串起來&#xff0c;本次學習呢&#xff0c;也是有很多的疑惑點&#xff0c;但是還是盡量的輸出內容&#xff0c;來幫助自己和在看文章的你來…

word運行時錯誤‘53’,文件未找到:MathPage.WLL,更改加載項路徑完美解決

最簡單的方法解決&#xff01;&#xff01;&#xff01;安裝Mathtype之后粘貼顯示&#xff1a;運行時錯誤‘53’&#xff0c;文件未找到&#xff1a;MathPage.WLLwin11安裝mathtype后會有這個錯誤&#xff0c;這是由于word中加載項加載mathtype路徑出錯導致的&#xff0c;這時候…

React實現列表拖拽排序

本文主要介紹一下React實現列表拖拽排序方法&#xff0c;具體樣式如下圖首先&#xff0c;簡單展示一下組件的數據結構 const CodeSetting props > {const {$t, // 國際化翻譯函數vm, // 視圖模型數據vm: {CodeSet: { Enable [], …

將 MySQL 表數據導出為 CSV 文件

目錄 一、實現思路 二、核心代碼 1. 數據庫連接部分 2. 數據導出核心邏輯 3. CSV文件寫入 三、完整代碼實現 五、輸出結果 一、實現思路 建立數據庫連接 查詢目標表的數據總量和具體數據 獲取表的列名作為CSV文件的表頭 將查詢結果轉換為二維數組格式 使用Hutool工具…

一文讀懂RAG:從生活場景到核心邏輯,AI“查資料答題”原來這么簡單

一文讀懂RAG&#xff1a;從生活場景到核心邏輯&#xff0c;AI“查資料答題”原來這么簡單 要理解 RAG&#xff08;Retrieval-Augmented Generation&#xff0c;檢索增強生成&#xff09;&#xff0c;不需要先背復雜公式&#xff0c;我們可以從一個生活場景切入——它本質是讓AI…

git將當前分支推送到遠端指定分支

在 Git 中&#xff0c;將當前本地分支推送到遠程倉庫的指定分支&#xff0c;可以使用 git push 命令&#xff0c;并指定本地分支和遠程分支的映射關系。 基本語法 git push <遠程名稱> <本地分支名>:<遠程分支名><遠程名稱>&#xff1a;通常是 origin&…

【Linux】線程封裝

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 一、為什么需要封裝線程庫&#xff1f; pthread的痛點&#xff1a; 封裝帶來的好處&#xff1a; 二、線程封裝核心代碼解析 1. 頭文件定義&#xff08;Thread.hpp&a…

智慧交通管理信號燈通信4G工業路由器應用

在交通信號燈管理中傳統的有線通訊&#xff08;光纖、網線&#xff09;存在部署成本高、偏遠區域覆蓋難、故障維修慢等問題&#xff0c;而4G工業路由器憑借無線化、高穩定、強適配的特性&#xff0c;成為信號燈與管控平臺間的數據傳輸核心&#xff0c;適配多場景需求。智慧交通…

《Python Flask 實戰:構建一個可交互的 Web 應用,從用戶輸入到智能響應》

《Python Flask 實戰:構建一個可交互的 Web 應用,從用戶輸入到智能響應》 一、引言:從“Hello, World!”到“你好,用戶” 在 Web 應用的世界里,最打動人心的功能往往不是炫酷的界面,而是人與系統之間的真實互動。一個簡單的輸入框,一句個性化的回應,往往能讓用戶感受…

開發效率翻倍:資深DBA都在用的MySQL客戶端利器

MySQL 連接工具&#xff08;也稱為客戶端或圖形化界面工具&#xff0c;GUI Tools&#xff09;是數據庫開發、管理和運維中不可或缺的利器。它們比命令行更直觀&#xff0c;能極大提高工作效率。以下是一份主流的 MySQL 連接工具清單&#xff0c;并附上了它們的優缺點和適用場景…

基于Docker和Kubernetes的CI/CD流水線架構設計與優化實踐

基于Docker和Kubernetes的CI/CD流水線架構設計與優化實踐 本文分享了在生產環境中基于Docker和Kubernetes構建高效可靠的CI/CD流水線的實戰經驗&#xff0c;包括業務場景、技術選型、詳細方案、踩坑與解決方案&#xff0c;以及最終的總結與最佳實踐&#xff0c;幫助后端開發者快…

Trae x 圖片素描MCP一鍵將普通圖片轉換為多風格素描效果

目錄前言一、核心工具與優勢解析二、操作步驟&#xff1a;從安裝到生成素描效果第一步&#xff1a;獲取MCP配置代碼第二步&#xff1a;下載第三步&#xff1a;在 Trae 中導入 MCP 配置并建立連接第四步&#xff1a;核心功能調用三、三大素描風格差異化應用四.總結前言 在設計創…