使用 Java 原生或 Hutool 工具包编写非对称加解密的工具类

1、什么是非对称加密

使用一对(2个)密钥:一个用于加密信息,另一个则用于解密信息。有“公钥(Public Key)”和“私钥(Private Key)”之分。

非对称加密的“公钥”和“私钥”是成对出现(就像“梁山伯”与“祝英台”一样,世界上独一无二的一对),需要使用工具一起同时生成。但是通过公钥推算不出私钥是什么,同样的,通过私钥也推算不出公钥长什么样(“梁山伯”丢失了那“祝英台”也失去意义)。

按照密钥依据性质划分,将其中的一个向外界公开,称为公钥;另一个则自己保留,称为私钥。

大多数情况下,公钥(Public key)用于数据加密,私钥(Private key)用于数据解密。但是并不是绝对的。也就是说:可以使用公钥加密数据,然后使用私钥解密数据。也可以使用私钥加密数据,然后使用公钥解密数据

但是:

1、私钥加密的数据,只能对应的公钥才能解密出来,私钥自己无法解密

2、公钥加密的数据,也是只有对应的私钥才能解密出来,公钥自己也无法解密。

 

2、使用 Java 原生编写非对称加解密工具类

package com.study.util;import java.security.*;
import javax.crypto.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;/*** @author CSDN 流放深圳* @description Java原生的非对称加密工具类* @create 2024-04-13 12:30* @since 1.0.0*/
public class NativeSecurityUtil {/*** 生成一对公钥&私钥(仅供测试使用,实际应用上只能生成一次,然后把公钥和私钥保存下来。切忌在业务中每次都调用此方法,否则造成秘钥丢失,数据不可解密!!!)* @return*/public static Map<String, String> generateKey() {Map<String, String> map = new HashMap<>();try{// 生成密钥对KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(1024); // 设置密钥长度为 1024 位KeyPair keyPair = keyPairGenerator.generateKeyPair();PublicKey publicObj = keyPair.getPublic();PrivateKey privateObj = keyPair.getPrivate();String publicKey = Base64.getEncoder().encodeToString(publicObj.getEncoded());String privateKey = Base64.getEncoder().encodeToString(privateObj.getEncoded());map.put("publicKey", publicKey);map.put("privateKey", privateKey);}catch (Exception e){e.printStackTrace();}return map;}/****************************** 【方式一:私钥加密 & 公钥解密】  ***********************************************//*** 【方式一】私钥加密** @param str        待加密字符串* @param privateKey 私钥* @return*/public static String encryptByPrivateKey(String str, String privateKey) {String result = null;try{byte[] encoded = Base64.getDecoder().decode(privateKey);PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encoded);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateObj = keyFactory.generatePrivate(privateKeySpec);Cipher cipherForEncryption = Cipher.getInstance("RSA");cipherForEncryption.init(Cipher.ENCRYPT_MODE, privateObj);//要加密的字符串转为 byte 类型byte[] originalBytes = str.getBytes("UTF-8");byte[] encryptedBytes = cipherForEncryption.doFinal(originalBytes);result = Base64.getEncoder().encodeToString(encryptedBytes);}catch (Exception e){e.printStackTrace();}return result;}/*** 【方式一】公钥解密** @param str       待解密字符串* @param publicKey 公钥* @return*/public static String decryptByPublicKey(String str, String publicKey) {String result = null;try{byte[] encoded = Base64.getDecoder().decode(publicKey);X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encoded);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicObj = keyFactory.generatePublic(publicKeySpec);Cipher cipherForDecryption = Cipher.getInstance("RSA");cipherForDecryption.init(Cipher.DECRYPT_MODE, publicObj);byte[] decryptedBytes = cipherForDecryption.doFinal(Base64.getDecoder().decode(str));result = new String(decryptedBytes, "UTF-8");}catch (Exception e){e.printStackTrace();}return result;}/****************************** 【方式二:公钥加密 & 私钥解密】  ***********************************************//*** 【方式二】公钥加密* @param str* @param publicKey* @return*/public static String encryptByPublicKey(String str, String publicKey) {String result = null;try{byte[] encoded = Base64.getDecoder().decode(publicKey);X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encoded);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicObj = keyFactory.generatePublic(publicKeySpec);Cipher cipherForEncryption = Cipher.getInstance("RSA");cipherForEncryption.init(Cipher.ENCRYPT_MODE, publicObj);//要加密的字符串转为 byte 类型byte[] originalBytes = str.getBytes("UTF-8");byte[] encryptedBytes = cipherForEncryption.doFinal(originalBytes);result = Base64.getEncoder().encodeToString(encryptedBytes);}catch (Exception e){e.printStackTrace();}return result;}/*** 【方式二】私钥解密* @param str* @param privateKey* @return*/public static String decryptByPrivateKey(String str, String privateKey) {String result = null;try{byte[] encoded = Base64.getDecoder().decode(privateKey);PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encoded);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateObj = keyFactory.generatePrivate(privateKeySpec);Cipher cipherForDecryption = Cipher.getInstance("RSA");cipherForDecryption.init(Cipher.DECRYPT_MODE, privateObj);byte[] decryptedBytes = cipherForDecryption.doFinal(Base64.getDecoder().decode(str));result = new String(decryptedBytes, "UTF-8");}catch (Exception e){e.printStackTrace();}return result;}/*** 测试* @param args*/public static void main(String[] args) {//首先生成一对公钥&私钥,记得保存下来Map<String, String> map = generateKey();String privateKey = map.get("privateKey");String publicKey = map.get("publicKey");System.out.println("私钥 privateKey=" + privateKey);System.out.println("公钥 publicKey=" + publicKey);String str = "CSDN流放深圳666";System.out.println("测试字符串=" + str);System.out.println("*********************** 【方式一:私钥加密 & 公钥解密】 *************************");String encrypt = encryptByPrivateKey(str, privateKey);System.out.println("【方式一】私钥加密结果 encrypt=" + encrypt);String decrypt = decryptByPublicKey(encrypt, publicKey);System.out.println("【方式一】公钥解密结果 decrypt=" + decrypt);System.out.println("*********************** 【方式二:公钥加密 & 私钥解密】 *************************");String encrypt222 = encryptByPublicKey(str, publicKey);System.out.println("【方式二】公钥加密结果 encrypt222=" + encrypt222);String decrypt222 = decryptByPrivateKey(encrypt222, privateKey);System.out.println("【方式二】私钥解密结果 decrypt222=" + decrypt222);}
}

测试结果:

私钥 privateKey=MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJd【因数据太长,省略掉后面的结果】
公钥 publicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5b【因数据太长,省略掉后面的结果】
测试字符串=CSDN流放深圳666
*********************** 【方式一:私钥加密 & 公钥解密】 *************************
【方式一】私钥加密结果 encrypt=Zx5loAwOM2C2mxHz8Yz/rn0e9+/y/9OX【因数据太长,省略掉后面的结果】
【方式一】公钥解密结果 decrypt=CSDN流放深圳666
*********************** 【方式二:公钥加密 & 私钥解密】 *************************
【方式二】公钥加密结果 encrypt222=H7dL/HArwa7QqXT8+hi25pC69w【因数据太长,省略掉后面的结果】
【方式二】私钥解密结果 decrypt222=CSDN流放深圳666

3、使用 Hutool 工具包编写非对称加解密工具类

这里演示的是 hutool 最新工具包 5.8.27(2024年4月13日)的工具类。hutool 工具包有很多组件,可以查看官网:https://hutool.cn/docs/#/?id=%f0%9f%93%9a%e7%ae%80%e4%bb%8b

模块介绍
hutool-aopJDK动态代理封装,提供非IOC下的切面支持
hutool-bloomFilter布隆过滤,提供一些Hash算法的布隆过滤
hutool-cache简单缓存实现
hutool-core核心,包括Bean操作、日期、各种Util等
hutool-cron定时任务模块,提供类Crontab表达式的定时任务
hutool-crypto加密解密模块,提供对称、非对称和摘要算法封装
hutool-dbJDBC封装后的数据操作,基于ActiveRecord思想
hutool-dfa基于DFA模型的多关键字查找
hutool-extra扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等)
hutool-http基于HttpUrlConnection的Http客户端封装
hutool-log自动识别日志实现的日志门面
hutool-script脚本执行封装,例如Javascript
hutool-setting功能更强大的Setting配置文件和Properties封装
hutool-system系统参数调用封装(JVM信息等)
hutool-jsonJSON实现
hutool-captcha图片验证码实现
hutool-poi针对POI中Excel和Word的封装
hutool-socket基于Java的NIO和AIO的Socket封装
hutool-jwtJSON Web Token (JWT)封装实现

可以根据需求对每个模块单独引入,也可以通过引入 hutool-all 方式引入所有模块。 

pom.xml 依赖

        <!-- hutool 加解密工具包 https://mvnrepository.com/artifact/cn.hutool/hutool-crypto --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-crypto</artifactId><version>5.8.27</version></dependency>

代码示例:

package com.study.util;import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;import java.util.HashMap;
import java.util.Map;/*** @author CSDN 流放深圳* @description Hutool 非对称加解密工具类* @create 2024-04-13 12:50* 参考链接:https://hutool.cn/docs/#/crypto/非对称加密-AsymmetricCrypto?id=%e4%bb%8b%e7%bb%8d* @since 1.0.0*/
public class HutoolSecurityUtil {/****************************** 【方式一:私钥加密 & 公钥解密】  ***********************************************//*** 【方式一】私钥加密** @param str        待加密字符串* @param privateKey 私钥* @return*/public static String encryptByPrivateKey(String str, String privateKey) {if (StrUtil.isEmpty(str)) return null;RSA rsa = new RSA(privateKey, null);return rsa.encryptBase64(str, KeyType.PrivateKey);}/*** 【方式一】公钥解密** @param str       待解密字符串* @param publicKey 公钥* @return*/public static String decryptByPublicKey(String str, String publicKey) {if (StrUtil.isEmpty(str)) return null;RSA rsa = new RSA(null, publicKey);byte[] decrypt = rsa.decrypt(str, KeyType.PublicKey);return StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8);}/****************************** 【方式二:公钥加密 & 私钥解密】  ***********************************************//*** 【方式二】公钥加密* @param str* @param publicKey* @return*/public static String encryptByPublicKey(String str, String publicKey) {if (StrUtil.isEmpty(str)) return null;RSA rsa = new RSA(null, publicKey);return rsa.encryptBase64(str, KeyType.PublicKey);}/*** 【方式二】私钥解密* @param str* @param privateKey* @return*/public static String decryptByPrivateKey(String str, String privateKey) {if (StrUtil.isEmpty(str)) return null;RSA rsa = new RSA(privateKey, null);byte[] decrypt = rsa.decrypt(str, KeyType.PrivateKey);return StrUtil.str(decrypt, CharsetUtil.CHARSET_UTF_8);}/*** 测试** @param args*/public static void main(String[] args) {//首先生成一对公钥&私钥,记得保存下来Map<String, String> map = generateKey();String privateKey = map.get("privateKey");String publicKey = map.get("publicKey");System.out.println("私钥 privateKey=" + privateKey);System.out.println("公钥 publicKey=" + publicKey);String str = "让天下没有难写的代码 Come on baby!";System.out.println("测试字符串=" + str);System.out.println("*********************** 【方式一:私钥加密 & 公钥解密】 *************************");String encrypt = encryptByPrivateKey(str, privateKey);System.out.println("【方式一】私钥加密结果 encrypt=" + encrypt);String decrypt = decryptByPublicKey(encrypt, publicKey);System.out.println("【方式一】公钥解密结果 decrypt=" + decrypt);System.out.println("*********************** 【方式二:公钥加密 & 私钥解密】 *************************");String encrypt222 = encryptByPublicKey(str, publicKey);System.out.println("【方式二】公钥加密结果 encrypt222=" + encrypt222);String decrypt222 = decryptByPrivateKey(encrypt222, privateKey);System.out.println("【方式二】公钥解密结果 decrypt222=" + decrypt222);}/*** 生成一对公钥&私钥(仅供测试使用,实际应用上只能生成一次,然后把公钥和私钥保存下来。切忌在业务中每次都调用此方法,否则造成秘钥丢失,数据不可解密!!!)*/public static Map<String, String> generateKey() {Map<String, String> map = new HashMap<>();RSA rsa = new RSA();String privateKey = rsa.getPrivateKeyBase64();//获得私钥String publicKey = rsa.getPublicKeyBase64();//获得公钥map.put("privateKey", privateKey);map.put("publicKey", publicKey);return map;}}

测试结果:

私钥 privateKey=MIICdgIBADANBgkqhkiG9w0BAQEFAASC【因数据太长,省略掉后面的结果】
公钥 publicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ【因数据太长,省略掉后面的结果】
测试字符串=让天下没有难写的代码 Come on baby!
*********************** 【方式一:私钥加密 & 公钥解密】 *************************
【方式一】私钥加密结果 encrypt=lAM1vSIgBzSmck97G/oLeGBiiMkrk【因数据太长,省略掉后面的结果】
【方式一】公钥解密结果 decrypt=让天下没有难写的代码 Come on baby!
*********************** 【方式二:公钥加密 & 私钥解密】 *************************
【方式二】公钥加密结果 encrypt222=U5ETStEvfxFqbAEU+TgCnQNqD+【因数据太长,省略掉后面的结果】
【方式二】公钥解密结果 decrypt222=让天下没有难写的代码 Come on baby!

需要注意的是,使用工具类生成一对公钥和私钥后,需要保存起来,且私钥不能对外泄露,否则后续找不到,直接导致之前的数据无法加解密。

—  end —

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

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

相关文章

c++24.4.13-const修饰指针

1、const修饰指针-常量指针 2、const修饰常量-指针常量 3、const既修饰指针又修饰常量 示例

maven之pom中的build标签

1、build标签分类 1.1、全局配置&#xff08;project build&#xff09; 针对整个项目的所有情况都有效。 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"htt…

什么?你设计接口什么都不考虑?

如果让你设计一个接口&#xff0c;你会考虑哪些问题&#xff1f; 1.接口参数校验 接口的入参和返回值都需要进行校验。 入参是否不能为空&#xff0c;入参的长度限制是多少&#xff0c;入参的格式限制&#xff0c;如邮箱格式限制 返回值是否为空&#xff0c;如果为空的时候是…

R语言数据可视化:基本绘图系统

目录 plot函数 par函数 hist函数 boxplot函数 plot函数应用实战 全局参数 R语言中有三大绘图系统包括基本绘图系统&#xff0c;Lattice绘图系统&#xff0c;ggplot2绘图系统 基本绘图系统 在R语言中&#xff0c;以下函数通常用于创建和定制图形&#xff1a; plot 函数…

僵尸进程和孤儿进程

目录 引言僵尸进程僵尸进程的状态僵尸进程周边知识 孤儿进程孤儿进程的状态 进程中的其他状态①.R---表示进程运行状态。②.S---表示进程的休眠状态。(进程什么都没做)③T 和 t 进程的运行、阻塞和挂起运行阻塞挂起状态&#xff1a; 引言 今天我们来将僵尸进程和孤儿进程以及其…

暴力枚举法

虽然暴力枚举法有时候效率低&#xff0c;时间复杂度高&#xff0c;但是在面对小规模数据集的时候&#xff0c;暴力枚举法往往是很好的思维利器。 B: 01 串的熵&#xff08;5分&#xff09; 问题描述 #include <iostream> #include <cmath> #include <algorithm…

【前端】es-drager 图片同比缩放 缩放比 只修改宽 只修改高

【前端】es-drager 图片同比缩放 缩放比 ES Drager 拖拽组件 (vangleer.github.io) 核心代码 //初始宽 let width ref(108)//初始高 let height ref(72)//以下两个变量 用来区分是单独的修改宽 还是高 或者是同比 //缩放开始时的宽 let oldWidth 0 //缩放开始时的高 let o…

【好用】推荐10套后端管理系统前端模板

后台管理系统前端模板是开发者在构建后台管理系统时使用的一种工具&#xff0c;它提供了预先设计好的界面和组件&#xff0c;以帮助开发者快速搭建出功能完善、用户体验良好的管理系统。以下是V哥整理的10款流行的后台管理系统前端模板&#xff0c;它们基于不同的技术栈和设计理…

【研发日记】CANoe自动化测试的配置方式(三)——SystemVariables数组方式

文章目录 前言 一、例程功能 二、仿真ECU 三、SystemVariables数组&#xff1a; 四、测试模块 五、测试运行效果 六、分析和应用 总结 前言 近期在做的一个自动化测试项目&#xff0c;尝试了一种以前没用过的测试配置方式&#xff0c;感觉效果还不错。然后又回顾了一下以…

Redis数据持久化 AOF RDB

Redis数据持久化 AOF RDB 1、单点 redis 的问题2、主从复制2.1 命令传播 3、Redis的持久化3.1 AOF写回策略重写机制后台重写 3.2 RDB&#xff08;默认方式&#xff09;RDB 方式&#xff1a;执行快照时&#xff0c;数据能被修改吗&#xff1f;RDB 方式总结 3.3 RDB 和 AOF 组合&…

场景:如何做数据清理

如果数据清理简单粗暴按时间进行清理&#xff0c;同时时间字段并没有增加索引就会出问题 如果没有增加索引&#xff0c;他就会进行全表扫描&#xff0c;并且会给全表的数据上一个x锁 会阻塞其他的线程 解决方案参考阿里云DMS数据清理方案 这个SQL查询的目的是从名为table_hol…

Unity之PUN实现多人联机射击游戏的优化(Section 3)

目录 &#x1f4a3;一、准备工作 &#x1f4a3;二、生成弹头脚本的编写 &#x1f4a3;三、实现发射和伤害同步 手雷都加了在给狗剩加个火箭筒不过分吧。效果看GIF动图&#xff0c;分别是单机和联机的效果。 添加火箭筒依旧是在原有的基础上更改&#xff0c;我查看火箭筒模型…