Java实现RSA密钥生成、加密解密、加签验签

一、RSA算法核心概述

RSA是目前应用最广泛的非对称加密算法 ,核心特征是使用一对密钥(公钥、私钥)完成数据交互,两个密钥数学关联但无法由其中一个推导出另一个,彻底解决对称加密密钥传输的安全难题。

1.1 核心特性

  • 公钥(Public Key):公开透明,可对外分发,主要用于加密数据、验证签名

  • 私钥(Private Key):绝对保密,仅持有者留存,主要用于解密数据、生成签名

  • 核心逻辑:公钥加密、私钥解密(保证数据保密性);私钥加签、公钥验签(保证数据完整性、真实性、不可抵赖性)

1.2 基础数学原理(极简易懂)

RSA的安全性基于大整数质因数分解难题,核心数学流程如下:

  1. 随机选取两个不相等的大质数p、q;

  2. 计算模数 N = p * q;

  3. 计算欧拉函数 φ(N) = (p-1)*(q-1);

  4. 选取公钥指数e(常用65537,满足1<e<φ(N)且与φ(N)互质);

  5. 计算私钥指数d(e关于φ(N)的模逆元,满足 e*d ≡ 1 (mod φ(N)));

  6. 最终:公钥=(N,e),私钥=(N,d)。

加密公式:C = M\^e \\bmod N (M为明文,C为密文)

解密公式:M = C\^d \\bmod N

二、RSA核心功能场景区分

很多开发者容易混淆加密解密、加签验签,两者的使用场景、密钥用法、核心目的完全不同:

功能 密钥使用规则 核心目的 适用场景
加密/解密 公钥加密,私钥解密 保证数据保密性,数据仅私钥持有者可读取 传输隐私数据(密码、手机号、密钥)
加签/验签 私钥加签,公钥验签 保证数据完整性、真实性、不可抵赖 接口请求、文件校验、交易确认

三、Java实现RSA完整流程

Java通过java.securityjavax.crypto原生包实现RSA,无需引入第三方依赖,本文实现:密钥对生成、公钥加密、私钥解密、私钥加签、公钥验签全流程,并逐行解析原理。

3.1 前置工具说明

  • 密钥算法:RSA

  • 加密填充方式:RSA/ECB/PKCS1Padding(通用标准,兼容绝大多数场景)

  • 签名算法:SHA256withRSA(SHA256哈希+RSA加密签名,安全性高于MD5)

  • 密钥长度:2048位(1024位已不安全,4096位性能较低,2048位为最优选择)

3.2 完整可运行代码

java 复制代码
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * RSA非对称加密工具类
 * 功能:密钥对生成、公钥加密、私钥解密、私钥加签、公钥验签
 */
public class RSAUtil {

    // 密钥算法
    private static final String RSA_ALGORITHM = "RSA";
    // 加密算法+填充模式
    private static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
    // 签名算法
    private static final String SIGN_ALGORITHM = "SHA256withRSA";
    // 密钥长度(2048位)
    private static final int KEY_SIZE = 2048;

    /**
     * 1. 生成RSA公私钥对
     */
    public static KeyPair generateRSAKeyPair() throws Exception {
        // 获取密钥对生成器实例
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        // 初始化密钥长度
        keyPairGenerator.initialize(KEY_SIZE);
        // 生成密钥对
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 2. 公钥加密
     * @param data 原始明文数据
     * @param publicKey 公钥
     * @return Base64编码后的密文
     */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        // 获取加密器实例
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        // 初始化加密器为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 执行加密
        byte[] encryptBytes = cipher.doFinal(data.getBytes());
        // 密文Base64编码(方便传输存储)
        return Base64.getEncoder().encodeToString(encryptBytes);
    }

    /**
     * 3. 私钥解密
     * @param encryptData Base64编码的密文
     * @param privateKey 私钥
     * @return 解密后的明文
     */
    public static String decrypt(String encryptData, PrivateKey privateKey) throws Exception {
        // 获取解密器实例
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        // 初始化解密器为解密模式
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // Base64解码密文
        byte[] encryptBytes = Base64.getDecoder().decode(encryptData);
        // 执行解密
        byte[] decryptBytes = cipher.doFinal(encryptBytes);
        return new String(decryptBytes);
    }

    /**
     * 4. 私钥加签(生成数字签名)
     * @param data 原始数据
     * @param privateKey 私钥
     * @return Base64编码的签名
     */
    public static String sign(String data, PrivateKey privateKey) throws Exception {
        // 获取签名对象
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        // 初始化签名对象(私钥签名)
        signature.initSign(privateKey);
        // 传入待签名数据
        signature.update(data.getBytes());
        // 生成签名并Base64编码
        byte[] signBytes = signature.sign();
        return Base64.getEncoder().encodeToString(signBytes);
    }

    /**
     * 5. 公钥验签(验证数据合法性)
     * @param data 原始数据
     * @param signStr 签名字符串
     * @param publicKey 公钥
     * @return 验签结果 true=合法 false=篡改/伪造
     */
    public static boolean verify(String data, String signStr, PublicKey publicKey) throws Exception {
        // 获取签名验证对象
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        // 初始化验签对象(公钥验签)
        signature.initVerify(publicKey);
        // 传入待验证原始数据
        signature.update(data.getBytes());
        // Base64解码签名
        byte[] signBytes = Base64.getDecoder().decode(signStr);
        // 执行验签
        return signature.verify(signBytes);
    }

    // 测试主方法
    public static void main(String[] args) throws Exception {
        // 1. 生成密钥对
        KeyPair keyPair = generateRSAKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println("公钥:" + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        System.out.println("私钥:" + Base64.getEncoder().encodeToString(privateKey.getEncoded()));

        // 待测试明文
        String plainText = "Java RSA 加密解密加签验签测试!123456";
        System.out.println("\n原始明文:" + plainText);

        // 2. 公钥加密
        String encryptStr = encrypt(plainText, publicKey);
        System.out.println("加密密文:" + encryptStr);

        // 3. 私钥解密
        String decryptStr = decrypt(encryptStr, privateKey);
        System.out.println("解密明文:" + decryptStr);

        // 4. 私钥加签
        String signStr = sign(plainText, privateKey);
        System.out.println("数据签名:" + signStr);

        // 5. 公钥验签(正常数据)
        boolean verifyResult1 = verify(plainText, signStr, publicKey);
        System.out.println("正常数据验签结果:" + verifyResult1);

        // 6. 篡改数据后验签(模拟数据被篡改)
        String errorText = "篡改后的RSA测试数据";
        boolean verifyResult2 = verify(errorText, signStr, publicKey);
        System.out.println("篡改数据验签结果:" + verifyResult2);
    }
}

四、逐步骤原理与作用详解

4.1 RSA密钥对生成(核心基础)

执行代码

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);

keyPairGenerator.initialize(KEY_SIZE);

KeyPair keyPair = keyPairGenerator.generateKeyPair();

原理与作用

  1. 获取密钥生成器:通过Java安全工厂获取RSA算法专用密钥生成器,绑定底层加密算法实现;

  2. 初始化密钥长度:2048位指定了模数N的长度,长度越长,破解难度越高,但加密解密速度越慢,2048位是安全与性能的平衡点;

  3. 生成密钥对:程序自动执行前文数学逻辑(选取大质数、计算N、φ(N)、e、d),生成配对的公钥和私钥,两个密钥绑定唯一数学关系。

关键特点:每次生成的密钥对均不重复,私钥绝对无法通过公钥逆向推导。

4.2 公钥加密(保障数据保密性)

核心流程

获取加密器 → 初始化为加密模式 → 明文转字节数组 → 执行RSA加密 → Base64编码输出

原理与作用

  1. Cipher加密器 :Java加密核心类,RSA/ECB/PKCS1Padding是标准填充模式,解决原始RSA无法加密短数据、数据对齐问题,兼容所有主流系统;

  2. 加密模式初始化Cipher.ENCRYPT_MODE绑定公钥,确定加密逻辑为「公钥加密」;

  3. 加密运算:底层执行 C = M\^e \\bmod N 公式,将明文转为不可直接读取的密文;

  4. Base64编码:加密后的密文是二进制字节数组,Base64编码后转为字符串,方便HTTP传输、日志打印、数据库存储。

使用意义:任何人都可以用公钥加密数据,但只有对应的私钥能解密,彻底防止传输过程中数据泄露。

4.3 私钥解密(还原原始数据)

核心流程

获取解密器 → 初始化为解密模式 → Base64解码密文 → 执行解密 → 转明文字符串

原理与作用

  1. 解密绑定私钥Cipher.DECRYPT_MODE绑定私钥,只有持有对应私钥的服务,才能触发解密逻辑;

  2. 解密运算:底层执行 M = C\^d \\bmod N 公式,通过私钥指数d还原明文;

  3. 数据还原:将解密后的字节数组转为字符串,得到原始业务数据。

核心约束 :公钥加密的密文,只能由对应私钥解密,其他私钥无法破解,保障数据专属保密性。

4.4 私钥加签(生成数字签名)

核心流程

获取签名工具 → 私钥初始化签名器 → 传入原始数据 → 生成签名 → Base64编码

原理与作用

签名的本质是:对数据的哈希值进行私钥加密,区别于直接加密原始数据。

  1. SHA256哈希:先对原始数据进行SHA256哈希运算,生成固定长度的哈希值,数据哪怕修改1个字符,哈希值会完全改变,保障数据完整性;

  2. 私钥加密哈希值 :用私钥对哈希值加密生成签名,因为私钥唯一,签名具有唯一性、不可伪造性

  3. 签名作用:证明数据由私钥持有者发送,且数据未被篡改、不可抵赖。

4.5 公钥验签(校验数据合法性)

核心流程

获取验签工具 → 公钥初始化验签器 → 传入原始数据 → 解码签名 → 校验匹配性

原理与作用

  1. 公钥解密签名:用公钥解密签名,得到原始数据的哈希值;

  2. 二次哈希比对:对接收的原始数据重新计算SHA256哈希值,与解密出的哈希值对比;

  3. 校验结果判定:一致则说明数据未篡改、签名合法;不一致则说明数据被修改或签名伪造。

核心价值:解决数据篡改、身份伪造、交易抵赖问题,是接口鉴权、数据校验的核心方案。

五、常见问题与注意事项

5.1 加密数据长度限制

RSA单次加密数据长度有限制:密钥长度/8 - 11(2048位密钥最大加密245字节数据)。如需加密大文本,需使用「RSA+AES」混合加密:RSA加密AES密钥,AES加密原始数据。

5.2 密钥格式规范

  • 公钥默认X509编码格式,对外分发;

  • 私钥默认PKCS8编码格式,严禁对外泄露;

  • 存储传输密钥必须Base64编码,避免格式错乱。

5.3 算法安全性

  • 禁止使用1024位密钥(已被暴力破解);

  • 禁止使用MD5withRSA签名(MD5哈希碰撞漏洞),统一使用SHA256withRSA;

  • 必须携带填充模式,避免使用无填充原始RSA。

六、总结

  1. RSA密钥对基于大整数分解难题生成,公钥公开、私钥保密,是所有功能的基础;

  2. 加密解密 :公钥加密、私钥解密,核心解决数据保密性,防止数据泄露;

  3. 加签验签 :私钥加签、公钥验签,核心解决数据完整性、真实性、不可抵赖性

  4. Java原生API可完美实现RSA全功能,无需第三方依赖,2048位密钥+SHA256withRSA是生产环境最优组合。

相关推荐
wear工程师1 小时前
ThreadLocal 在线程池里为什么会串数据:别只会答内存泄漏
java·后端
Iruoyaoxh1 小时前
栈和队列~
java·开发语言
审小匠OpenCPAi1 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
码上上班2 小时前
docker课程
java·docker·容器
腻害兔2 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
达子6662 小时前
第9章_HarmonyOs图解 用Java开发UI
java·ui·harmonyos
龙虾PRO4 小时前
能源与股票量化核心差异,AI全链路落地实操手册
java·面试·职场和发展
llwszx4 小时前
【Java/Go后端手撸原生Agent(第九篇):Plan-and-Execute规划模式——从“走一步看一步“到“先谋后动“】
java·python·golang·agent开发·plan模式·规划执行模式
ZJH__GO4 小时前
网络编程v2--多客户端互通
java·运维·服务器·开发语言·计算机网络