java RSA加密/解密(附带源码)_java rsa加密解密工具类
目录
-
项目背景与动机
-
加密技术概述
-
对称加密 vs 非对称加密
-
RSA 算法的历史与应用
-
-
RSA 算法数学原理
-
大素数与整数分解难题
-
欧拉函数与模反元素
-
公钥、私钥生成流程
-
加密与解密数学公式
-
-
Java 环境与依赖
-
JDK 版本与安全策略
-
Maven/Gradle 依赖配置
-
-
项目结构设计
-
包结构与模块划分
-
工具类、核心类与测试类
-
-
核心代码详解
-
密钥对生成(KeyPairGenerator)
-
公钥私钥对象处理(KeyFactory & KeySpec)
-
加解密流程(Cipher)
-
Base64 编解码工具
-
异常与日志处理
-
单元测试与集成测试
-
-
进阶话题
-
填充模式(OAEP vs PKCS#1 v1.5)
-
分段加密与大数据处理
-
数字签名与验签
-
混合加密(RSA + AES)
-
-
性能优化与安全强化
-
密钥长度与性能权衡
-
硬件加速与安全模块(HSM)
-
防止旁路攻击与时间攻击
-
密钥管理与安全存储
-
-
项目实战:Web 服务中的 RSA 应用
-
基于 Spring Boot 的加密 REST 接口
-
前端 JavaScript 与后端 RSA 交互
-
-
CI/CD 集成与自动化测试
-
项目总结与展望
-
参考资料与延伸阅读
1. 项目背景与动机
在当今网络安全威胁不断升级的背景下,保障数据私密性和完整性已成为各行业的核心需求。传统的对称加密算法在密钥分发和管理上存在瓶颈,而非对称加密因其“公钥可公开、私钥保密”的特性,成为安全传输、数字签名等场景的首选。RSA 算法作为最经典的非对称加密方案之一,被广泛应用于 SSL/TLS 握手、电子邮件加密、软件授权保护等。
本项目旨在使用 Java 原生 API(JCA/JCE)从零实现 RSA 加密/解密的完整流程,并配以详尽注释与解释,帮助开发者理解底层原理、掌握实战技巧,为后续在生产环境中构建安全模块打好基础。通过本项目,你将收获:
-
非对称加密的数学基础与实现原理
-
Java 中密钥生成、转换、加解密的完整代码示例
-
常见填充模式、分段加密、数字签名的进阶应用
-
安全性能权衡、硬件加速、密钥管理的最佳实践
2. 加密技术概述
2.1 对称加密 vs 非对称加密
-
对称加密
-
使用同一密钥进行加密和解密
-
速度快、适合大数据量加解密
-
最大痛点:密钥分发与管理
-
典型算法:AES、DES、3DES
-
-
非对称加密
-
使用一对密钥:公钥(公开)与私钥(保密)
-
加密速度较慢,但可解决密钥分发问题
-
典型算法:RSA、DSA、ECC
-
对称加密和非对称加密常常结合使用,在实际系统中采用“混合加密”:使用非对称算法安全地交换对称密钥,再用对称算法处理大数据,以兼顾安全与性能。
2.2 RSA 算法的历史与应用
-
提出者:Ron Rivest、Adi Shamir、Leonard Adleman
-
年份:1977 年
-
核心原理:基于大整数分解的计算难题,安全性依赖于当前无高效拆分大合数的算法
-
应用场景:
-
SSL/TLS 握手:交换对称会话密钥
-
数字证书:X.509、PKCS#12
-
电子邮件加密:S/MIME、PGP
-
数字签名:代码签名、文档签名
-
3. RSA 算法数学原理
3.1 大素数与整数分解难题
RSA 的安全基础在于:给定大合数 N=p×q,很难在可接受时间内找到其两个大素因数 p 和 q。本项目为了演示,使用 1024 位或 2048 位素数,但在工业级系统中建议 3072 位及以上。
3.2 欧拉函数与模反元素
-
欧拉函数 φ(n):对于 n=p×q,φ(n)=(p−1)(q−1)
-
模反元素 d:满足 e×d≡1 (mod φ(n)),可用扩展欧几里得算法求解
3.3 公钥、私钥生成流程
-
随机选取两个大素数 p、q
-
计算 N=p×q
-
计算 φ(n)=(p−1)(q−1)
-
选定公钥指数 e,满足 1<e<φ(n),且 gcd(e,φ(n))=1
-
计算私钥指数 d,使得 e×d≡1 mod φ(n)
-
生成公钥 (e, N),私钥 (d, N)
3.4 加密与解密数学公式
-
加密:C = M^e mod N
-
解密:M = C^d mod N
其中 M 必须小于 N,实际系统中对大于 N 的数据进行分段加密或借助填充模式处理。
4. Java 环境与依赖
4.1 JDK 版本与安全策略
-
推荐使用 JDK 11+,已内置最新的 JCA/JCE 安全策略
-
如需使用超过 128 位密钥,请安装并配置 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy
4.2 Maven/Gradle 依赖配置
本项目依赖于 Java 标准库,若需额外日志或测试框架,可在 pom.xml
中添加:
org.slf4j slf4j-api 1.7.36 ch.qos.logback logback-classic 1.2.11 org.junit.jupiter junit-jupiter 5.9.0 test
Gradle 示例:
dependencies { implementation \'org.slf4j:slf4j-api:1.7.36\' implementation \'ch.qos.logback:logback-classic:1.2.11\' testImplementation \'org.junit.jupiter:junit-jupiter:5.9.0\'}
5. 项目结构设计
5.1 包结构与模块划分
src/main/java └─ com.example.rsa ├─ encryption // 加解密核心类 │ ├─ RSAKeyUtil.java │ ├─ RSAEncryptor.java │ └─ RSADecryptor.java ├─ utils // 工具类 │ └─ Base64Util.java └─ App.java // 演示入口src/test/java └─ com.example.rsa └─ RSAEncryptorTest.java
5.2 工具类、核心类与测试类
-
RSAKeyUtil:密钥生成与读写
-
RSAEncryptor:公钥加密方法封装
-
RSADecryptor:私钥解密方法封装
-
Base64Util:统一 Base64 编解码接口
-
App:示例演示和命令行测试
-
单元测试:覆盖正向与错误场景
6. 核心代码详解
以下完整代码已整合至单个文件中,带有详细注释。
package com.example.rsa;import javax.crypto.Cipher;import java.security.*;import java.security.spec.*;import java.util.Base64;/** * 整合版 RSA 工具类,包含密钥生成、公钥加密、私钥解密功能。 */public class RSAUtil { // 默认密钥长度(1024、2048、3072) private static final int KEY_SIZE = 2048; private static final String ALGORITHM = \"RSA\"; private static final String TRANSFORMATION = \"RSA/ECB/OAEPWithSHA-256AndMGF1Padding\"; /** * 生成 RSA 密钥对 * * @return KeyPair 对象,包含公钥和私钥 * @throws NoSuchAlgorithmException */ public static KeyPair generateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM); keyGen.initialize(KEY_SIZE); return keyGen.generateKeyPair(); } /** * 将公钥转换为 Base64 字符串 * * @param publicKey 公钥对象 * @return Base64 编码后的公钥 */ public static String publicKeyToBase64(PublicKey publicKey) { byte[] encoded = publicKey.getEncoded(); return Base64.getEncoder().encodeToString(encoded); } /** * 将私钥转换为 Base64 字符串 * * @param privateKey 私钥对象 * @return Base64 编码后的私钥 */ public static String privateKeyToBase64(PrivateKey privateKey) { byte[] encoded = privateKey.getEncoded(); return Base64.getEncoder().encodeToString(encoded); } /** * 从 Base64 公钥字符串恢复 PublicKey 对象 * * @param base64PublicKey Base64 编码的公钥 * @return PublicKey 对象 * @throws GeneralSecurityException */ public static PublicKey base64ToPublicKey(String base64PublicKey) throws GeneralSecurityException { byte[] decoded = Base64.getDecoder().decode(base64PublicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); return keyFactory.generatePublic(keySpec); } /** * 从 Base64 私钥字符串恢复 PrivateKey 对象 * * @param base64PrivateKey Base64 编码的私钥 * @return PrivateKey 对象 * @throws GeneralSecurityException */ public static PrivateKey base64ToPrivateKey(String base64PrivateKey) throws GeneralSecurityException { byte[] decoded = Base64.getDecoder().decode(base64PrivateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); return keyFactory.generatePrivate(keySpec); } /** * 使用公钥加密数据 * * @param plainText 明文字符串 * @param publicKey 公钥对象 * @return Base64 编码的密文 * @throws GeneralSecurityException */ public static String encrypt(String plainText, PublicKey publicKey) throws GeneralSecurityException { Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encrypted = cipher.doFinal(plainText.getBytes()); return Base64.getEncoder().encodeToString(encrypted); } /** * 使用私钥解密数据 * * @param cipherText Base64 编码的密文 * @param privateKey 私钥对象 * @return 解密后的明文字符串 * @throws GeneralSecurityException */ public static String decrypt(String cipherText, PrivateKey privateKey) throws GeneralSecurityException { Cipher cipher = Cipher.getInstance(TRANSFORMATION); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decoded = Base64.getDecoder().decode(cipherText); byte[] decrypted = cipher.doFinal(decoded); return new String(decrypted); } /** * 示例主方法,演示全流程 */ public static void main(String[] args) { try { // 1. 生成密钥对 KeyPair keyPair = generateKeyPair(); String pubKeyStr = publicKeyToBase64(keyPair.getPublic()); String priKeyStr = privateKeyToBase64(keyPair.getPrivate()); System.out.println(\"公钥(Base64):\"); System.out.println(pubKeyStr); System.out.println(\"\\n私钥(Base64):\"); System.out.println(priKeyStr); // 2. 加密 String message = \"RSA 加密测试数据\"; String cipherText = encrypt(message, keyPair.getPublic()); System.out.println(\"\\n原文:\" + message); System.out.println(\"密文(Base64):\" + cipherText); // 3. 解密 String decrypted = decrypt(cipherText, keyPair.getPrivate()); System.out.println(\"\\n解密后:\" + decrypted); } catch (Exception e) { e.printStackTrace(); } }}
7. 进阶话题
7.1 填充模式(OAEP vs PKCS#1 v1.5)
-
PKCS#1 v1.5
-
兼容性好,但存在已知填充攻击
-
-
OAEP(Optimal Asymmetric Encryption Padding)
-
基于随机填充,更安全
-
在 JDK 中可通过
RSA/ECB/OAEPWithSHA-256AndMGF1Padding
指定
-
7.2 分段加密与大数据处理
由于 RSA 最大加密数据长度受到密钥长度与填充开销限制,超过此长度需分段:
-
将数据按块大小(keySize/8 - 填充开销)切分
-
对每个块分别加密,最后合并 Base64 字符串
7.3 数字签名与验签
-
签名:使用私钥对消息摘要(如 SHA-256)签名
-
验签:使用公钥验证签名是否匹配原消息
-
Java 示例:
Signature sig = Signature.getInstance(\"SHA256withRSA\");sig.initSign(privateKey);sig.update(dataBytes);byte[] signature = sig.sign();
7.4 混合加密(RSA + AES)
混合加密是工业实践的标准模式:
-
生成一次性对称密钥(AES)
-
使用 AES 加密大数据
-
使用 RSA 公钥加密 AES 密钥
-
接收方用私钥解密出 AES 密钥,再解密大数据
8. 性能优化与安全强化
8.1 密钥长度与性能权衡
-
1024 位:性能好但安全性边缘
-
2048 位:推荐生产环境
-
3072–4096 位:最高安全级别,但性能开销大
8.2 硬件加速与安全模块(HSM)
-
利用硬件安全模块加速大整数运算
-
提供密钥隔离存储,防止私钥泄露
8.3 防止旁路攻击与时间攻击
-
常量时间运算:避免分支泄露比特信息
-
掩码技术:对运算输入进行随机掩码处理
8.4 密钥管理与安全存储
-
不应将私钥硬编码在源代码中
-
可使用 Java KeyStore 或外部密码管理系统(如 HashiCorp Vault)
9. 项目实战:Web 服务中的 RSA 应用
9.1 基于 Spring Boot 的加密 REST 接口
-
创建 Spring Boot 项目,加入上述 RSAUtil
-
定义
/encrypt
、/decrypt
两个控制器 -
请求中传输 Base64 编码的数据
示例 Controller:
@RestController@RequestMapping(\"/api/rsa\")public class RSAController { private final PublicKey publicKey = ...; // 从配置或文件加载 private final PrivateKey privateKey = ...; @PostMapping(\"/encrypt\") public String encrypt(@RequestBody String plainText) throws Exception { return RSAUtil.encrypt(plainText, publicKey); } @PostMapping(\"/decrypt\") public String decrypt(@RequestBody String cipherText) throws Exception { return RSAUtil.decrypt(cipherText, privateKey); }}
9.2 前端 JavaScript 与后端 RSA 交互
-
使用 jsencrypt 库在浏览器端进行公钥加密
-
将后端返回的公钥注入前端,完成端到端加密流程
10. CI/CD 集成与自动化测试
-
单元测试:覆盖密钥生成、加解密正向与异常场景
-
集成测试:启动 Spring Boot 应用,测试
/encrypt
与/decrypt
接口 -
安全扫描:接入 Snyk、OWASP Dependency-Check,保证依赖无已知漏洞
11. 项目总结与展望
本文从理论、实现、优化到实战完整覆盖了 Java 版 RSA 加密/解密项目,可帮助读者:
-
掌握 RSA 算法及 Java 实战技巧
-
理解填充模式、分段加密、混合加密等进阶概念
-
学会在 Web 服务中安全集成 RSA 模块
未来可继续拓展:
-
ECC(椭圆曲线加密)实现
-
多方安全计算与门限签名
-
区块链交易签名与验证
12. 参考资料与延伸阅读
-
《Java 加密与解密实战》
-
《Applied Cryptography》 by Bruce Schneier
-
Oracle 官方文档:Java Cryptography Architecture (JCA)
-
RFC 8017:PKCS #1 v2.2