> 技术文档 > java RSA加密/解密(附带源码)_java rsa加密解密工具类

java RSA加密/解密(附带源码)_java rsa加密解密工具类


目录

  1. 项目背景与动机

  2. 加密技术概述

    1. 对称加密 vs 非对称加密

    2. RSA 算法的历史与应用

  3. RSA 算法数学原理

    1. 大素数与整数分解难题

    2. 欧拉函数与模反元素

    3. 公钥、私钥生成流程

    4. 加密与解密数学公式

  4. Java 环境与依赖

    1. JDK 版本与安全策略

    2. Maven/Gradle 依赖配置

  5. 项目结构设计

    1. 包结构与模块划分

    2. 工具类、核心类与测试类

  6. 核心代码详解

    1. 密钥对生成(KeyPairGenerator)

    2. 公钥私钥对象处理(KeyFactory & KeySpec)

    3. 加解密流程(Cipher)

    4. Base64 编解码工具

    5. 异常与日志处理

    6. 单元测试与集成测试

  7. 进阶话题

    1. 填充模式(OAEP vs PKCS#1 v1.5)

    2. 分段加密与大数据处理

    3. 数字签名与验签

    4. 混合加密(RSA + AES)

  8. 性能优化与安全强化

    1. 密钥长度与性能权衡

    2. 硬件加速与安全模块(HSM)

    3. 防止旁路攻击与时间攻击

    4. 密钥管理与安全存储

  9. 项目实战:Web 服务中的 RSA 应用

    1. 基于 Spring Boot 的加密 REST 接口

    2. 前端 JavaScript 与后端 RSA 交互

  10. CI/CD 集成与自动化测试

  11. 项目总结与展望

  12. 参考资料与延伸阅读


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 公钥、私钥生成流程

  1. 随机选取两个大素数 p、q

  2. 计算 N=p×q

  3. 计算 φ(n)=(p−1)(q−1)

  4. 选定公钥指数 e,满足 1<e<φ(n),且 gcd(e,φ(n))=1

  5. 计算私钥指数 d,使得 e×d≡1 mod φ(n)

  6. 生成公钥 (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 最大加密数据长度受到密钥长度与填充开销限制,超过此长度需分段:

  1. 将数据按块大小(keySize/8 - 填充开销)切分

  2. 对每个块分别加密,最后合并 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)

混合加密是工业实践的标准模式:

  1. 生成一次性对称密钥(AES)

  2. 使用 AES 加密大数据

  3. 使用 RSA 公钥加密 AES 密钥

  4. 接收方用私钥解密出 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 接口

  1. 创建 Spring Boot 项目,加入上述 RSAUtil

  2. 定义 /encrypt/decrypt 两个控制器

  3. 请求中传输 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