java案例RSA分段加密解密,签名验签,公钥加密私钥解密,私钥加密公钥解密,解密乱码怎么解决

一. 原理

非对称加密算法是一种密钥的保密方法。
非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。

二. 场景

多用于银行等安全级别较高系统

三. 实现原理

整体过程描述:首先通过RSA生成工具生成公玥密钥,分发给各系统,各系统在调接口时,利用私约生成签名,公玥加密数据,被调用方利用公玥验签,私约解密数据。

四.java案例

package com.atguigu.springcloud.util.interrup;import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.net.URLDecoder;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;public class RSAUtil04 {/*** 加密算法RSA*/public static final String KEY_ALGORITHM = "RSA";/*** 签名算法*/public static final String SIGNATURE_ALGORITHM = "MD5withRSA";/*** 获取公钥的key*/private static final String PUBLIC_KEY = "RSAPublicKey";/*** 获取私钥的key*/private static final String PRIVATE_KEY = "RSAPrivateKey";/*** RSA最大加密明文大小*/private static final int MAX_ENCRYPT_BLOCK = 117;/*** RSA最大解密密文大小*/private static final int MAX_DECRYPT_BLOCK = 128;/*** 生成密钥对(公钥和私钥)** @return* @throws Exception*/public static Map<String, Object> genKeyPair() throws Exception {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);keyPairGen.initialize(1024);KeyPair keyPair = keyPairGen.generateKeyPair();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}/*** 获取公钥字符串** @param keyMap 密钥对* @return 公钥字符串* @throws Exception 异常*/public static String getPublicKeyStr(Map<String, Object> keyMap) throws Exception {//获得map中的公钥对象 转为key对象Key key = (Key) keyMap.get(PUBLIC_KEY);//编码返回字符串return encryptBASE64(key.getEncoded());}/*** 获取私钥字符串** @param keyMap 密钥对* @return 私钥字符串* @throws Exception 异常*/public static String getPrivateKeyStr(Map<String, Object> keyMap) throws Exception {//获得map中的私钥对象 转为key对象Key key = (Key) keyMap.get(PRIVATE_KEY);//编码返回字符串return encryptBASE64(key.getEncoded());}/*** 将byte[]进行Base64编码** @param key 待编码的byte[]* @return 编码后的字符串*/public static String encryptBASE64(byte[] key) {return Base64.getMimeEncoder().encodeToString(key);}/*** 用私钥对信息生成数字签名** @param data 已加密数据* @param privateKey 私钥(BASE64编码)** @return* @throws Exception*/public static String sign(byte[] data, String privateKey) throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initSign(privateK);signature.update(data);return Base64Utils.encode(signature.sign());}/*** 校验数字签名** @param data 已加密数据* @param publicKey 公钥(BASE64编码)* @param sign 数字签名** @return* @throws Exception**/public static boolean verify(byte[] data, String publicKey, String sign)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PublicKey publicK = keyFactory.generatePublic(keySpec);Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initVerify(publicK);signature.update(data);return signature.verify(Base64Utils.decode(sign));}/*** 私钥解密** @param encryptedData 已加密数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, privateK);int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/*** 公钥解密** @param encryptedData 已加密数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, publicK);int inputLen = encryptedData.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(encryptedData, offSet, MAX_DECRYPT_BLOCK);} else {cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_DECRYPT_BLOCK;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/*** 公钥加密** @param data 源数据* @param publicKey 公钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, String publicKey)throws Exception {byte[] keyBytes = Base64Utils.decode(publicKey);X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key publicK = keyFactory.generatePublic(x509KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, publicK);int inputLen = data.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(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/*** 私钥加密** @param data 源数据* @param privateKey 私钥(BASE64编码)* @return* @throws Exception*/public static byte[] encryptByPrivateKey(byte[] data, String privateKey)throws Exception {byte[] keyBytes = Base64Utils.decode(privateKey);PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, privateK);int inputLen = data.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(data, offSet, MAX_ENCRYPT_BLOCK);} else {cache = cipher.doFinal(data, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);i++;offSet = i * MAX_ENCRYPT_BLOCK;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}/*** 获取私钥** @param keyMap 密钥对* @return* @throws Exception*/public static String getPrivateKey(Map<String, Object> keyMap)throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return Base64Utils.encode(key.getEncoded());}/*** 获取公钥** @param keyMap 密钥对* @return* @throws Exception*/public static String getPublicKey(Map<String, Object> keyMap)throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return Base64Utils.encode(key.getEncoded());}public static void main(String[] args) {try {String json = "{\n" +"    \"successful\": false,\n" +"    \"code\": 1010,\n" +"    \"message\": \"参数【_identificationId】没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限没有该字段查询权限\",\n" +"    \"timestamp\": 1695881640402,\n" +"    \"requestId\": \"4d8a793df32141d1bf6fb0a2bd527fa8\"\n" +"}";byte[] data = json.getBytes();Map<String, Object> stringObjectMap = genKeyPair();String pubK = getPublicKeyStr(stringObjectMap);String priK = getPrivateKeyStr(stringObjectMap);//System.out.println("---------------------------------公钥加密私钥解密-----------------------------------");// 获取签名String sign = RSAUtil04.sign(data, priK);boolean flag = RSAUtil04.verify(data, pubK, sign);byte[] sendByte = RSAUtil04.encryptByPublicKey(data, pubK);// 把加密数据转string// 这是实际接口中要发送的数据String sendStr = Base64Utils.encode(sendByte);System.out.println("encode1="+sendStr);// string转二进制byte[] sendBytes = Base64Utils.decode(sendStr);// 数据解密byte[] resultByte = new byte[0];resultByte = RSAUtil04.decryptByPrivateKey(sendBytes, priK);String resultStr = new String(resultByte);System.out.println("resultStr1="+resultStr);System.out.println("---------------------------------私钥加密公钥解密-----------------------------------");byte[] sendByte2 = RSAUtil04.encryptByPrivateKey(data, priK);// 把加密数据转string// 这是实际接口中要发送的数据String sendStr2 = Base64Utils.encode(sendByte2);System.out.println("encode2="+sendStr2);// string转二进制byte[] sendBytes2 = Base64Utils.decode(sendStr2);// 数据解密byte[] resultByte2 = new byte[0];resultByte2 = RSAUtil04.decryptByPublicKey(sendBytes2, pubK);String resultStr2 = new String(resultByte2);System.out.println("resultStr2="+resultStr2);System.out.println("--------------------------用别人返回的密文公钥解密------------------------------");//密文String data2 = "HMoBWOOr2z7yTEl0O4lwkNzJM8ntzuSNfViIQfbM8vCoeaVCvVub41n51QMsPgklD2cMa17dFp3SpkUGwRz2f7c7ckA85RYZm0UQtUB7yjYGNwKdiyGnHOu4WVmL3SoOFC2gYJWV0gznsiGOS02WJ3FRLNzneW+tCk1RA7jCDx+WL1f+K7AFklOFRAoJAqFq7VkPTaRNyjDFY4VYZwUGR+KxDPwvGJctaCRwvcZ0DmhSTYoKrqCbrUlV62WcUO4WPjVMphil8V8rLZ+E5xL675a75MTLhpw/QEUMfXOtpDz3YTMWvYrfzV/un/TPnuxVseEmQDjamJ1sOD4VPesY34whHS+82n2ds5NQZG7IzgQ3maPMbDjWHk4CNFj00LWFAia4dlIs/tbiPQBMkQx33jwmcc5uI3PUEhVg+lJIuJKEbr7R9oKBUGbimhmE8C6XlK7kKw97cisWX5tJQsnHpMKwr+tZy7pY+lZX/AT8Ek1624aHx4jDU7MHdGbv1zuJS95AziLce7GEUExeRvs93Mj3KHZgD6rVO+KcU5JlfE2Wj176iuaWRjAtib0neZpMRqTmH4FZdFPZRfP1YpWrZrguwyeRhWjEs+h6Khf6QBQRRxdcOf6OrJz1ykP7Eq7+OoTjqSViq5ARfhqjWbwyUwVZ/JMWa3DAxCR9m+xYlmI=";byte[] sendBytes4 = Base64Utils.decode(data2);// 数据解密byte[] resultByte4 = new byte[0];String pubk2="***公钥***";resultByte4 = RSAUtil04.decryptByPublicKey(sendBytes4, pubk2);String resultStr4 = new String(resultByte4);//加上下面这行解密就不会出现乱码原因:分段解密的时候汉字 字节代表3个字节,在解密最大长度分界如果3个字节被分隔成了两段转成string就会乱码了resultStr4 = URLDecoder.decode(resultStr4);System.out.println("resultStr4="+resultStr4);} catch (Exception e) {e.printStackTrace();}}
}

五.发现的问题:对方返回的密文在本地使用公钥解密时乱码

效果:
在这里插入图片描述
返回值:
在这里插入图片描述

分段解密的时候汉字 字节代表3个字节,在解密最大长度分界如果3个字节被分隔成了两段转成string就会乱码了
加上下面这样代码就OK
resultStr4 = URLDecoder.decode(resultStr4);
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/157111.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

纯 CSS 实现瀑布流布局的方法

纯 CSS 实现瀑布流布局的方法 这种方式兼容性不是很好&#xff0c;全部支持需要些时间&#xff0c;但是目前是可以使用 css 写出来的 display: grid; grid-template-columns: repeat(4, 1fr); grid-gap: 10px; grid-template-rows: masonry;全部的 css .container {display:…

凉鞋的 Godot 笔记 108. 第二个通识:增删改查

在这一篇&#xff0c;我们来学习此教程的第二个通识&#xff0c;即&#xff1a;增删改查。 增删改查我们不只是一次接触到了。 在最先接触的场景窗口中&#xff0c;我们是对 Node 进行增删改查。 在文件系统窗口中&#xff0c;我们是对文件&文件夹进行增删改查&#xff1…

【单片机】18-红外线遥控

一、红外遥控背景知识 1.人机界面 &#xff08;1&#xff09;当面操作&#xff1a;按键&#xff0c;旋转/触摸按键&#xff0c;触摸屏 &#xff08;2&#xff09;遥控操作&#xff1a;红外遥控&#xff0c;433M/2.4G无线通信【穿墙能力强】&#xff0c;蓝牙-WIFI-Zigbee-LoRa等…

jupyter 切换虚拟环境

当前只有两个环kernel 我已经创建了很多虚拟环境&#xff0c;如何在notebook中使用这些虚拟环境呢&#xff1f;请看下面 比如说我要添加nlp 这个虚拟环境到notebook中 1. 切换到nlp环境 2. 安装如下模块 pip install ipykernel 3. 执行如下命令 python -m ipykernel install …

【IDEA项目个别类爆红,但是项目可以正常运行】

打开项目时发现idea个别类爆红,但是项目可以正常运行 问题原因&#xff1a;Idea本身的问题&#xff0c;可能是其缓存问题&#xff0c;导致爆红 解决方案&#xff1a;重置Idea 很多时候排查不出代码问题&#xff0c;就尝试一下此操作。 选择目录&#xff1a;File–>Invalida…

今日头条文章采集ChatGPT3.5/4.0驱动浏览器改写文章软件说明文档

大家好了&#xff0c;我是淘小白~ 今天给大家介绍的软件是一个款驱动浏览器改写文章的软件&#xff0c;下面给大家做一下介绍说明&#xff1a; 一、软件语言 Python编写的&#xff0c;使用的库是selenium库 二、具体逻辑 1、整理头条文章网址&#xff0c;需要自己整理&…

【广州华锐互动】钢厂铸锻部VR沉浸式实训系统

随着科技的不断进步&#xff0c;虚拟现实(VR)技术已成为当今最具潜力的技术之一。在钢铁行业中&#xff0c;VR虚拟仿真实训已经被广泛应用于培训和教育领域&#xff0c;特别是钢铁厂铸锻部&#xff0c;通过VR技术&#xff0c;可以大大提高培训效率&#xff0c;降低培训成本&…

多域名SSL数字证书是什么呢

多域名SSL数字证书是众多SSL数字证书中最灵活的一款SSL证书产品。一般一张SSL证书只能保护一个域名&#xff0c;即使能保护多个域名站点&#xff0c;证书保护的域名类型也有限制(通配符SSL数字证书)。多域名SSL数字证书既能用一张SSL证书保护多个域名网站&#xff0c;又不限制域…

CentOS 7 服务器上创建新用户及设置用户密码有效期

一、创建用户 1、以 root 用户身份登录到 CentOS 服务器 2、运行以下命令以创建新用户&#xff1a; useradd -m -s /bin/bash username其中&#xff0c;username 是您要创建的新用户的用户名。该命令将创建一个新用户并为其分配一个主目录。3、运行以下命令以设置新用户的密码…

XPath在数据采集中的应用:从XML和HTML中提取数据

目录 一、XPath简介 二、XPath的语法 三、XPath在数据采集中的应用 四、XPath和其他数据格式 总结 在当今的数据驱动时代&#xff0c;从各种数据源中提取有用的信息变得至关重要。其中&#xff0c;XML和HTML作为主流的数据源格式&#xff0c;常常出现在我们的数据提取任务…

正点原子嵌入式linux驱动开发——Busybox根文件系统构建

前面已经移植了TF-A、Uboot和Linux kernel&#xff0c;就剩最后一个 rootfs(根文件系统)了&#xff0c;本章就来学习一下根文件系统的组成以及如何构建根文件系统。这是Linux系统移植的最后一步&#xff0c;根文件系统构建好以后就意味着拥有了一个完整的、可以运行的最小系统 …

【运维笔记】VMWare 另一个程序已锁定文件的一部分,进程无法访问

情景再现 这里使用的是VMware 17 解决办法 进入设置 点击选项&#xff0c;全选复制里面内容 进入文件夹&#xff0c;删除所有包含.lck后缀的文件和文件夹 再启动虚拟机即可

【Vue基础-数字大屏】加载动漫效果

一、需求描述 当网页正在加载而处于空白页面状态时&#xff0c;可以在该页面上显示加载动画提示。 二、步骤代码 1、全局下载npm install -g json-server npm install -g json-server 2、在src目录下新建文件夹mock&#xff0c;新建文件data.json存放模拟数据 {"one&…

基于片段的分子生成网络 (FLAG)使用方法及案例测评

本文来源于中国科技大学计算机科学与技术学院刘淇教授课题组于2023年发表在ICLR2023上的文章《MOLECULE GENERATION FOR TARGET PROTEIN BINDING WITH STRUCTURAL MOTIFS》。 在本文中&#xff0c;作者提出了一个基于片段的分子生成网络&#xff0c;FLAG &#xff08;Fragment …

如何在虚幻引擎中渲染动画?

大家好&#xff0c;今天我将展示如何在虚幻引擎中渲染动画&#xff0c;以及虚幻引擎渲染动画怎么设置的方法步骤。 需要提前了解&#xff1a; 虚幻引擎本地运行慢、渲染慢、本地配置不够&#xff0c;如何解决&#xff1f; 渲云云渲染支持虚幻引擎离线渲染&#xff0c;可批量…

钢筋智能测径仪 光圆与带肋钢筋均可检测!

在一个大规模、高效、连续的工业生产中&#xff0c;制造业正朝着自动化方向快速优化发展&#xff0c;这种自动化的生产需要快速、准确地分析控制生产工艺中的参数&#xff0c;超差及时提示&#xff0c;为操作工对工厂的运行和自我调节做出快速反应&#xff0c;人工操作越来越不…

SpringBootCMS漏洞复现分析

SpringBootCMS&#xff0c;极速开发&#xff0c;动态添加字段&#xff0c;自定义标签&#xff0c;动态创建数据库表并crud数据&#xff0c;数据库备份、还原&#xff0c;动态添加站点(多站点功能)&#xff0c;一键生成模板代码&#xff0c;让您轻松打造自己的独立网站&#xff…

【html】利用生成器函数和video元素,取出指定时间的视频画面

简言 有的时候想截取视频某一秒的视频画面。 手动截取操作麻烦&#xff0c;还得时刻关注视频播放时间。 于是&#xff0c;我搞出来了一个根据视频自动截取特定时间描述的页面。 效果 实现步骤 获取视频对象根据视频时长生成时间选择表单根据表单选择的时间和视频地址&#x…

用手势识别来测试视力?试试用百度AI来实现想法

文章目录 ⭐ 前言⭐ 灵感来源⭐ 项目准备⭐ 项目实现⭐ 不足与展望 ⭐ 前言 10月17日&#xff0c;以“生成未来&#xff08;PROMPT THE WORLD&#xff09;”为主题的百度世界2023将在北京首钢园举办。百度创始人、董事长兼首席执行官李彦宏将带来以“手把手教你做AI原生应用”…

校招C#面试题整理—Unity客户端

前言 博客已经1年多没有更新了&#xff0c;这一年主要在实习并准备秋招和春招&#xff0c;目前已经上岸Unity客户端岗位&#xff0c;现将去年校招遇到的一些面试题的事后整理分享出来。答案是笔者自己整理的不一定保证准确&#xff0c;欢迎大家在评论区指出。 Unity客户端岗的…