小易说IT 小易说IT

Java 极简 RSA 加密 + 签名演示代码

前置说明

  1. 使用 JDK 原生 java.security,不引入第三方包

  2. 加密采用 RSA/ECB/OAEPWithSHA-256AndMGF1Padding(推荐,替代不安全的 PKCS1-v1.5)

  3. 签名采用 SHA256withRSA(PSS 会复杂一点,这段是极简演示)

  4. 密钥 2048 bit;RSA 不适合加密长明文,示例只加密短字符串;生产一定是 RSA 传 AES key

  5. 编码:Base64(JDK11+ 自带 Base64)

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaDemo {

    public static void main(String[] args) throws Exception {
        // 1. 生成RSA密钥对
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair = keyGen.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

        // 转Base64方便打印、存储(实际项目可以存到配置/证书)
        String pubKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        String priKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        System.out.println("公钥:\n" + pubKeyBase64);
        System.out.println("私钥:\n" + priKeyBase64);

        // 原始明文
        String originText = "hello rsa test 123456";
        System.out.println("\n原始明文:" + originText);

        // ========== 加密:公钥加密 ==========
        byte[] cipherData = encrypt(originText.getBytes(), publicKey);
        String cipherBase64 = Base64.getEncoder().encodeToString(cipherData);
        System.out.println("RSA加密后密文(Base64): " + cipherBase64);

        // ========== 解密:私钥解密 ==========
        byte[] plainData = decrypt(Base64.getDecoder().decode(cipherBase64), privateKey);
        String plainText = new String(plainData);
        System.out.println("RSA解密结果:" + plainText);

        // ========== 签名:私钥签名 ==========
        byte[] signData = sign(originText.getBytes(), privateKey);
        String signBase64 = Base64.getEncoder().encodeToString(signData);
        System.out.println("\n签名值(Base64): " + signBase64);

        // ========== 验签:公钥验签 ==========
        boolean verifyOk = verify(originText.getBytes(), signData, publicKey);
        System.out.println("验签结果:" + verifyOk);

        // 模拟篡改测试
        String tamperText = "hello rsa test 123456 xxx";
        boolean verifyFail = verify(tamperText.getBytes(), signData, publicKey);
        System.out.println("篡改后验签:" + verifyFail);


        // ===== 演示:从Base64字符串还原密钥(网络传输、配置读取场景)=====
        PublicKey restorePub = getPublicKey(pubKeyBase64);
        PrivateKey restorePri = getPrivateKey(priKeyBase64);
        boolean verifyByRestoreKey = verify(originText.getBytes(), signData, restorePub);
        System.out.println("使用还原后的公钥验签:" + verifyByRestoreKey);
    }

    /**
     * RSA公钥加密 OAEP
     */
    public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * RSA私钥解密 OAEP
     */
    public static byte[] decrypt(byte[] cipherData, PrivateKey privateKey) throws Exception {
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(cipherData);
    }

    /**
     * SHA256withRSA 私钥签名
     */
    public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }

    /**
     * SHA256withRSA 公钥验签
     */
    public static boolean verify(byte[] data, byte[] signBytes, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(signBytes);
    }

    /**
     * Base64字符串 -> 公钥对象
     */
    public static PublicKey getPublicKey(String pubBase64) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(pubBase64);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(spec);
    }

    /**
     * Base64字符串 -> 私钥对象
     */
    public static PrivateKey getPrivateKey(String priBase64) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(priBase64);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(spec);
    }
}

重要生产提醒

  1. JDK8 自带这套 API,但部分老国产 JDK 可能缺少 OAEP 支持,此时只能降级 RSA/ECB/PKCS1Padding(不安全,仅兼容旧系统)

  2. 不要用 RSA 加密业务报文!标准方案:RSA 加密 AES 密钥 + AES 加密业务数据

  3. 签名优先推荐 RSASSA-PSS(SHA256withRSAandMGF1),安全性更高,上面代码是 SHA256withRSA 仅做演示

  4. 私钥严禁明文放配置文件,建议密钥管理服务 KMS

  5. 异常不要直接对外抛出堆栈,防止泄露密钥相关信息