基于hutool实现非对称加密(RSA和国密SM2)的加解密和加签验签
背景
对外服务的接口为了安全起见,往往需要进行相应的安全处理:数据加密传输和身份认证。数据加密传输有对称加密和非对称加密两种,为了更加安全起见采用非对称加密比较好些,身份认证则采用数字签名可以实现。
非对称加密缺点:加解密速度慢、RSA有最大长度要求。
方案一
仅采用非对称加密
RSA对内容长度的要求可以通过分组加解密解决
参考:https://blog.csdn.net/draven1122/article/details/55212252
方案二
非对称加密+对称加密
内容采用对称加密(AES)加密,非对称加密仅加密AES密钥
加密工具类可以使用:https://hutool.cn/docs/#/crypto/%E6%A6%82%E8%BF%B0
基于hutool中密码工具类实现的rsa和国密的非对称加解密算法和加签验签算法代码如下
maven依赖
<!-- huTool工具箱 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.22</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15to18</artifactId> <version>1.69</version> </dependency>
rsa非对称加密
package com.hdwang.test.hutool; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; import cn.hutool.crypto.asymmetric.Sign; import cn.hutool.crypto.asymmetric.SignAlgorithm; import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Base64; /** * @author wanghuidong * @date 2022/5/25 21:00 */ public class RsaTest { public static void main(String[] args) { String text = "人最宝贵的是生命.生命对每个人只有一次.人的一生应当这样度过:当他回首往事的时候,不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻.这样,在临死的时候,他能够说:“我已把自己的整个的生命和全部的精力献给了世界上最壮丽的事业---------为人类的解放而斗争.”"; System.out.println("原文:" + text); //生成公私钥对 KeyPair pair = SecureUtil.generateKeyPair("RSA"); PrivateKey privateKey = pair.getPrivate(); PublicKey publicKey = pair.getPublic(); //获得私钥 String privateKeyStr = bytesToBase64(privateKey.getEncoded()); System.out.println("私钥:" + privateKeyStr); //获得公钥 String publicKeyStr = bytesToBase64(publicKey.getEncoded()); System.out.println("公钥:" + publicKeyStr); RSA rsa = new RSA(privateKeyStr, publicKeyStr); System.out.println(rsa); //公钥加密,私钥解密 byte[] encrypt = rsa.encrypt(StrUtil.bytes(text, CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey); System.out.println("公钥加密:" + bytesToBase64(encrypt)); byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey); System.out.println("私钥解密:" + new String(decrypt,StandardCharsets.UTF_8)); // //私钥加密,公钥解密 // byte[] encrypt2 = rsa.encrypt(StrUtil.bytes(text, CharsetUtil.CHARSET_UTF_8), KeyType.PrivateKey); // System.out.println("私钥加密:" + bytesToBase64(encrypt2)); // byte[] decrypt2 = rsa.decrypt(encrypt2, KeyType.PublicKey); // System.out.println("公钥解密:" + bytesToBase64(decrypt2)); Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKeyStr, publicKeyStr); //签名 byte[] data = text.getBytes(StandardCharsets.UTF_8); byte[] signed = sign.sign(data); String signedStr = bytesToBase64(signed); System.out.println("签名:" + signedStr); //验证签名 boolean verify = sign.verify(data, base64ToBytes(signedStr)); System.out.println("验签:" + verify); } /** * 字节数组转Base64编码 * * @param bytes 字节数组 * @return Base64编码 */ private static String bytesToBase64(byte[] bytes) { byte[] encodedBytes = Base64.getEncoder().encode(bytes); return new String(encodedBytes, StandardCharsets.UTF_8); } /** * Base64编码转字节数组 * * @param base64Str Base64编码 * @return 字节数组 */ private static byte[] base64ToBytes(String base64Str) { byte[] bytes = base64Str.getBytes(StandardCharsets.UTF_8); return Base64.getDecoder().decode(bytes); } }
国密非对称加密(SM2)
package com.hdwang.test.hutool; import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.SM2; import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.util.Base64; /** * 国密非对称加解密和加签验签算法 * * @author wanghuidong * @date 2022/5/25 20:50 */ public class SmTest { public static void main(String[] args) { String text = "人最宝贵的是生命.生命对每个人只有一次.人的一生应当这样度过:当他回首往事的时候,不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻.这样,在临死的时候,他能够说:“我已把自己的整个的生命和全部的精力献给了世界上最壮丽的事业---------为人类的解放而斗争.”"; System.out.println("原文:" + text); KeyPair pair = SecureUtil.generateKeyPair("SM2"); byte[] privateKey = pair.getPrivate().getEncoded(); byte[] publicKey = pair.getPublic().getEncoded(); System.out.println("公钥:\n" + bytesToBase64(publicKey)); System.out.println("私钥:\n" + bytesToBase64(privateKey)); SM2 sm2 = SmUtil.sm2(privateKey, publicKey); // 公钥加密,私钥解密 String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey); System.out.println("加密后:" + encryptStr); String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey)); System.out.println("解密后:" + decryptStr); //加签 String sign = sm2.signHex(HexUtil.encodeHexStr(text)); System.out.println("签名:" + sign); //验签 boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(text), sign); System.out.println("验签:" + verify); } /** * 字节数组转Base64编码 * * @param bytes 字节数组 * @return Base64编码 */ private static String bytesToBase64(byte[] bytes) { byte[] encodedBytes = Base64.getEncoder().encode(bytes); return new String(encodedBytes, StandardCharsets.UTF_8); } /** * Base64编码转字节数组 * * @param base64Str Base64编码 * @return 字节数组 */ private static byte[] base64ToBytes(String base64Str) { byte[] bytes = base64Str.getBytes(StandardCharsets.UTF_8); return Base64.getDecoder().decode(bytes); } }
目前本人实现了一套简单的安全对外开放api的sdk,可以直接拿来使用,支持上述方案一和方案二。
https://github.com/hdwang123/openapi
参考文章:
https://www.cnblogs.com/pcheng/p/9629621.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版