小易说IT 小易说IT

Java RSA 加密 + 数字签名完整示例代码

要点说明:

  1. 密钥:RSA 2048,公钥加密,私钥解密私钥签名,公钥验签

  2. 加密填充:RSA/ECB/OAEPWithSHA-256AndMGF1Padding(推荐,安全,替代不安全的 PKCS1v1.5)

  3. 签名算法:SHA256withRSA(先对原文做 SHA256 哈希,再 RSA 私钥签名)

  4. 因为 RSA 加密长度有限,示例只加密短文本;生产中大文件用「AES 加密内容 + RSA 加密 AES 密钥」

  5. JDK 原生 java.security无需引入第三方包

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RsaDemo {

    // RSA 密钥长度
    private static final int KEY_SIZE = 2048;
    // 加密算法
    private static final String RSA_ALGORITHM = "RSA";
    // 加密模式填充
    private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
    // 签名算法
    private static final String SIGN_ALGORITHM = "SHA256withRSA";

    public static void main(String[] args) throws Exception {
        // 1. 生成RSA密钥对(公钥、私钥)
        KeyPair keyPair = generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 转Base64字符串,方便网络传输/存储
        String pubKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        String priKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        System.out.println("=== 公钥(Base64) ===");
        System.out.println(pubKeyBase64);
        System.out.println("=== 私钥(Base64) ===");
        System.out.println(priKeyBase64);

        // 原始明文
        String originText = "Hello RSA,测试RSA加密+数字签名!";
        System.out.println("\n原始明文:" + originText);

        // ========== RSA 加密解密演示 ==========
        // 公钥加密
        String encryptBase64 = encrypt(originText, pubKeyBase64);
        System.out.println("\n公钥加密结果(Base64):" + encryptBase64);
        // 私钥解密
        String decryptText = decrypt(encryptBase64, priKeyBase64);
        System.out.println("私钥解密结果:" + decryptText);

        // ========== RSA 签名验签演示 ==========
        // 私钥签名
        String signBase64 = sign(originText, priKeyBase64);
        System.out.println("\n私钥签名结果(Base64):" + signBase64);
        // 公钥验签
        boolean verifyResult = verify(originText, signBase64, pubKeyBase64);
        System.out.println("公钥验签结果:" + verifyResult);

        // 篡改原文测试:验签失败
        String tamperText = "Hello RSA,【被篡改】测试RSA加密+数字签名!";
        boolean verifyTamper = verify(tamperText, signBase64, pubKeyBase64);
        System.out.println("篡改后原文验签:" + verifyTamper);
    }

    /**
     * 生成RSA密钥对
     */
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        generator.initialize(KEY_SIZE, new SecureRandom());
        return generator.generateKeyPair();
    }

    /**
     * 公钥加密
     * @param plainText 明文
     * @param publicKeyBase64 base64公钥
     * @return base64密文
     */
    public static String encrypt(String plainText, String publicKeyBase64) throws Exception {
        // 还原公钥对象
        byte[] pubBytes = Base64.getDecoder().decode(publicKeyBase64);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(pubBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(spec);

        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptBytes = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encryptBytes);
    }

    /**
     * 私钥解密
     * @param cipherBase64 base64密文
     * @param privateKeyBase64 base64私钥
     * @return 明文
     */
    public static String decrypt(String cipherBase64, String privateKeyBase64) throws Exception {
        byte[] priBytes = Base64.getDecoder().decode(privateKeyBase64);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(priBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(spec);

        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] plainBytes = cipher.doFinal(Base64.getDecoder().decode(cipherBase64));
        return new String(plainBytes);
    }

    /**
     * 私钥签名
     * @param content 原文
     * @param privateKeyBase64 base64私钥
     * @return base64签名串
     */
    public static String sign(String content, String privateKeyBase64) throws Exception {
        byte[] priBytes = Base64.getDecoder().decode(privateKeyBase64);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(priBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(spec);

        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(content.getBytes());
        byte[] signBytes = signature.sign();
        return Base64.getEncoder().encodeToString(signBytes);
    }

    /**
     * 公钥验签
     * @param content 原文
     * @param signBase64 base64签名
     * @param publicKeyBase64 base64公钥
     * @return true=合法,false=篡改/签名不对
     */
    public static boolean verify(String content, String signBase64, String publicKeyBase64) throws Exception {
        byte[] pubBytes = Base64.getDecoder().decode(publicKeyBase64);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(pubBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(spec);

        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(content.getBytes());
        return signature.verify(Base64.getDecoder().decode(signBase64));
    }
}

运行输出示例

=== 公钥(Base64) ===
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlxxxx
=== 私钥(Base64) ===
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCAlxxxx

原始明文:Hello RSA,测试RSA加密+数字签名!

公钥加密结果(Base64):K5xxxx
私钥解密结果:Hello RSA,测试RSA加密+数字签名!

私钥签名结果(Base64):D8xxxx
公钥验签结果:true
篡改后原文验签:false

生产注意事项

  1. 不要裸 RSA:必须带填充,OAEP 优于旧的 PKCS#1 v1.5

  2. RSA 不能加密大数据:2048 位 RSA 最多加密 245 字节,业务中:AES 加密业务数据,RSA 加密 AES 密钥

  3. 私钥严禁明文硬编码,生产要密钥管理(KMS)

  4. 字符编码:代码里getBytes()默认平台编码,生产统一指定 StandardCharsets.UTF_8

  5. JDK 版本:Base64是 JDK8+;低版本要用 commons-codec

改造:加上 UTF-8(推荐上线版本)

把所有 content.getBytes() 替换为

content.getBytes(StandardCharsets.UTF_8)

记得 import java.nio.charset.StandardCharsets;


本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。

原文链接 https://www.yijunzhao.cc/archives/java-rsa-encryption-digital-signature-complete-example-code

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/