You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何用RSA公钥加密数据?及公钥加载异常解决

RSA公钥加密问题解决方法

先排查PEM格式问题

你遇到的java.security.InvalidKeyException: IOException: algid parse error not a sequence异常,大概率是PEM公钥格式不匹配导致的:

  • 确认PEM头部尾部:必须是-----BEGIN PUBLIC KEY-----(X.509格式)或-----BEGIN RSA PUBLIC KEY-----(PKCS#1格式),结尾需对应匹配。
  • 清理PEM时别留多余字符:去掉头部尾部后,只保留Base64编码内容,删除所有空格、换行以外的杂项(换行全删也可,但不能有其他符号)。
  • 格式不兼容处理:如果是PKCS#1格式的PEM,直接用X509EncodedKeySpec会报错——因为X509对应的是带算法标识的SubjectPublicKeyInfo结构,而PKCS#1只有纯RSA公钥数据。可以把PKCS#1格式转成X509格式再处理,或者直接用RSAPublicKeySpec生成公钥。

用JWK的n和e生成RSAPublicKey

是的,直接使用JWK中的n(模)和e(公钥指数)生成RSAPublicKey是更可靠的方案,步骤如下:

  1. Base64URL解码:JWK里的n和e是Base64URL编码,需要替换-为+、_为/,并补全=使长度为4的倍数。
  2. 转BigInteger:将解码后的字节数组转为正整数(BigInteger构造时传入1表示正数)。
  3. 构造公钥:通过RSAPublicKeySpec和KeyFactory生成RSAPublicKey。

代码示例

处理PEM公钥(兼容PKCS#1和X509)

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERSequence;

public class PublicKeyUtils {
    public static PublicKey getPublicKeyFromPEM(String pem) throws Exception {
        // 清理PEM内容
        String cleanedPem = pem.replaceAll("-----BEGIN (RSA )?PUBLIC KEY-----", "")
                               .replaceAll("-----END (RSA )?PUBLIC KEY-----", "")
                               .replaceAll("\\s+", "");

        byte[] keyBytes = Base64.getDecoder().decode(cleanedPem);

        try {
            // 尝试X509格式解析
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePublic(spec);
        } catch (Exception e) {
            // 转为X509格式(PKCS#1转X509)
            DERSequence algorithmSeq = new DERSequence(
                new ASN1ObjectIdentifier("1.2.840.113549.1.1.1"),
                new DERNull()
            );
            ASN1BitString publicKeyBitString = new DERBitString(keyBytes);
            DERSequence subjectPublicKeyInfo = new DERSequence(algorithmSeq, publicKeyBitString);
            byte[] x509Bytes = subjectPublicKeyInfo.getEncoded();

            X509EncodedKeySpec spec = new X509EncodedKeySpec(x509Bytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePublic(spec);
        }
    }
}

从JWK的n和e生成RSAPublicKey

import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.math.BigInteger;
import java.util.Base64;

public class JWKUtils {
    public static RSAPublicKey getRSAPublicKeyFromJWK(String n, String e) throws Exception {
        // 解码n
        String nBase64 = n.replace('-', '+').replace('_', '/');
        while (nBase64.length() % 4 != 0) {
            nBase64 += "=";
        }
        byte[] nBytes = Base64.getDecoder().decode(nBase64);
        BigInteger modulus = new BigInteger(1, nBytes);

        // 解码e
        String eBase64 = e.replace('-', '+').replace('_', '/');
        while (eBase64.length() % 4 != 0) {
            eBase64 += "=";
        }
        byte[] eBytes = Base64.getDecoder().decode(eBase64);
        BigInteger exponent = new BigInteger(1, eBytes);

        // 生成公钥
        RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return (RSAPublicKey) kf.generatePublic(spec);
    }
}

总结

  • 若PEM解析报错,优先检查格式类型,通过代码兼容两种格式即可解决。
  • 使用JWK的n和e生成公钥更稳定,避免了PEM格式混淆的问题,推荐优先采用这种方式。

内容的提问来源于stack exchange,提问作者Dany

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:27:42