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

使用BouncyCastle库加密文件时遇DER长度异常求助

RSA加密报错:java.io.IOException: DER length more than 4 bytes 排查与解决

问题背景

使用BouncyCastle库加密文本文件时抛出上述错误,实现代码及公钥文件内容如下:

实现代码

public class RSAEncryptFile {

    public static void main(String[] args)
    {

        String publicKeyFilename = "/Users/Rajesh/Desktop/pubkey";
        String inputFilename = "/Users/Rajesh/Desktop/test";
        String encryptedFilename = "/Users/Rajesh/Desktop/javaprogram";

        RSAEncryptFile rsaEncryptFile = new RSAEncryptFile();
        publicKeyFilename = "/Users/Rajesh/Desktop/pubkey";; 
        inputFilename = "/Users/Rajesh/Desktop/tesco.txt";
        encryptedFilename = "/Users/Rajesh/Desktop/javaprogram";
        rsaEncryptFile.encrypt(publicKeyFilename, inputFilename, encryptedFilename);

    }

    private void encrypt (String publicKeyFilename, String inputFilename, String encryptedFilename){

        try {

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            String value = "";
            String key = readFileAsString(publicKeyFilename);
            BASE64Decoder b64 = new BASE64Decoder();
            AsymmetricKeyParameter publicKey =
                    (AsymmetricKeyParameter) PublicKeyFactory.createKey(b64.decodeBuffer(key));
            AsymmetricBlockCipher e = new RSAEngine();
            e = new org.bouncycastle.crypto.encodings.PKCS1Encoding(e);
            e.init(true, publicKey);

            String inputdata = readFileAsString(inputFilename);
            byte[] messageBytes = inputdata.getBytes();
            int i = 0;
            int len = e.getInputBlockSize();
            while (i < messageBytes.length)
            {
                if (i + len > messageBytes.length)
                    len = messageBytes.length - i;

                byte[] hexEncodedCipher = e.processBlock(messageBytes, i, len);
                value = value + getHexString(hexEncodedCipher);
                i += e.getInputBlockSize();
            }

            System.out.println(value);
            BufferedWriter out = new BufferedWriter(new FileWriter(encryptedFilename));
            out.write(value);
            out.close();

        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

    public static String getHexString(byte[] b) throws Exception {
        String result = "";
        for (int i=0; i < b.length; i++) {
            result +=
                    Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
        }
        return result;
    }

    private static String readFileAsString(String filePath)
            throws java.io.IOException{
        StringBuffer fileData = new StringBuffer(1000);
        BufferedReader reader = new BufferedReader(
                new FileReader(filePath));
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
            buf = new char[1024];
        }
        reader.close();
        System.out.println(fileData.toString());
        return fileData.toString();
    }

} 

公钥文件内容

pub dsa1024 2019-07-29 [SC]
4EB9C4A3CEF9CCA26C1446G7H1D511656GH98D9E
uid [ultimate] TEST <TEST@test.com>
sub elg4096 2019-07-29 [E] 

问题根源

1. 公钥格式完全不匹配

你使用的是OpenPGP结构化公钥,包含用户ID、子密钥等多段信息,但代码中用PublicKeyFactory.createKey()尝试解析为RSA的DER编码公钥——该方法仅支持纯DER/Base64格式的单密钥数据,直接读取整个PGP公钥文件并Base64解码,必然导致DER格式解析失败。

2. 密钥算法与代码不兼容

公钥明确标注了dsa1024(签名密钥)和elg4096(加密子密钥),但代码中使用的是RSAEngine,DSA/ElGamal与RSA是不同的非对称加密算法,无法混用。


解决方法

方案一:改用BouncyCastle的PGP加密API

直接使用OpenPGP规范处理公钥和加密,步骤如下:

  1. 导入BouncyCastle的PGP相关依赖包
  2. 读取并解析PGP公钥环,提取加密子密钥
  3. 使用PGP加密流程处理文件

示例代码片段(读取PGP公钥):

FileInputStream keyIn = new FileInputStream(publicKeyFilename);
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(
    PGPUtil.getDecoderStream(keyIn), new JcaKeyFingerprintCalculator());
keyIn.close();

// 查找可用的加密公钥
PGPPublicKey encKey = null;
Iterator<PGPPublicKeyRing> rIt = pgpPub.getKeyRings();
while (rIt.hasNext() && encKey == null) {
    PGPPublicKeyRing kRing = rIt.next();
    Iterator<PGPPublicKey> kIt = kRing.getPublicKeys();
    while (kIt.hasNext()) {
        PGPPublicKey k = kIt.next();
        if (k.isEncryptionKey()) {
            encKey = k;
        }
    }
}

后续可基于encKey初始化PGP加密器,完成文件的加密(需遵循PGP规范的分块、压缩、封装流程)。

方案二:转换公钥格式

若无需OpenPGP特性,可通过工具从PGP公钥中导出纯ElGamal(或RSA)公钥的DER/Base64格式,再用原代码逻辑解析,但需注意算法匹配(代码中需替换为ElGamalEngine)。


其他代码优化点

  • 字符串拼接value = value + getHexString(...)效率极低,替换为StringBuilder
  • 弃用sun私有包的BASE64Decoder,改用BouncyCastle的org.bouncycastle.util.encoders.Base64
  • 分段加密时,需每次循环重新获取len = e.getInputBlockSize(),避免循环中修改len导致后续块大小错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:05:04