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

如何修改BouncyCastle PGP Java加密代码实现多段内容完整解密?

问题根源

你遇到的问题是因为每次调用encrypt方法都会生成一个完整独立的PGP加密消息包,而你直接把两个消息包的字节数据拼接写入同一个文件。GnuPG在默认解密时只会解析并输出第一个完整的PGP消息内容,所以只显示第一段文本。

解决方案

下面提供两种可行的解决思路,你可以根据需求选择:

方案1:合并明文后一次性加密(最简单)

如果不需要保留两段内容的独立性,直接把两段明文合并成一个字节数组,只调用一次encrypt方法生成单个PGP消息。这样GnuPG解密后会输出全部内容。

修改你的测试代码如下:

PGPPublicKey pubKey = PGPEncryptionTools.readPublicKeyFromCol(new FileInputStream(appProp.getKeyFileName()));
// 合并两段明文为一个字节数组
byte[] combinedText = "\nthis is some test text\nmore test text".getBytes();
byte[] encryptbytes = PGPEncryptionTools.encrypt(combinedText, pubKey, null, true, false);

FileOutputStream fos = new FileOutputStream("C:/Users/me/workspace/workspace/spring-batch-project/resources/encryptedfile.gpg");
fos.write(encryptbytes);
fos.flush();
fos.close();

方案2:支持多段独立内容的加密和解密(保留独立性)

如果你需要在同一个加密文件中保留两段内容的独立性(比如后续可以单独解密某一段),可以修改加密代码将多段内容打包到同一个PGP压缩流中,同时修改解密代码循环处理所有内容块。

修改加密方法

新增一个支持多段明文的加密方法:

import java.util.Arrays;

public static byte[] encryptMultiple(byte[][] clearDataList, PGPPublicKey encKey, String[] fileNames, boolean withIntegrityCheck, boolean armor) throws IOException, PGPException, NoSuchProviderException {
    // 处理文件名默认值
    if (fileNames == null || fileNames.length != clearDataList.length) {
        fileNames = new String[clearDataList.length];
        Arrays.fill(fileNames, PGPLiteralData.CONSOLE);
    }

    ByteArrayOutputStream encOut = new ByteArrayOutputStream();
    OutputStream out = encOut;
    if (armor) {
        out = new ArmoredOutputStream(out);
    }

    ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP);
    OutputStream cos = comData.open(bOut);

    PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
    try {
        // 循环写入每一段明文
        for (int i = 0; i < clearDataList.length; i++) {
            byte[] clearData = clearDataList[i];
            String fileName = fileNames[i];
            OutputStream pOut = lData.open(
                cos,
                PGPLiteralData.BINARY,
                fileName,
                clearData.length,
                new Date()
            );
            pOut.write(clearData);
            pOut.close(); // 关闭当前内容块的输出流
        }
    } finally {
        lData.close();
        comData.close();
    }

    // 加密压缩后的多段内容
    PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(
        new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_192)
            .setSecureRandom(new SecureRandom())
    );
    cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));
    
    byte[] bytes = bOut.toByteArray();
    OutputStream cOut = cPk.open(out, bytes.length);
    cOut.write(bytes);
    cOut.close();
    out.close();

    return encOut.toByteArray();
}

修改测试代码调用新方法

PGPPublicKey pubKey = PGPEncryptionTools.readPublicKeyFromCol(new FileInputStream(appProp.getKeyFileName()));
// 准备多段明文
byte[][] clearDataList = {
    "\nthis is some test text".getBytes(),
    "\nmore test text".getBytes()
};
byte[] encryptbytes = PGPEncryptionTools.encryptMultiple(clearDataList, pubKey, null, true, false);

FileOutputStream fos = new FileOutputStream("C:/Users/me/workspace/workspace/spring-batch-project/resources/encryptedfile.gpg");
fos.write(encryptbytes);
fos.flush();
fos.close();

修改解密代码支持多段内容

原解密代码只处理第一个内容块,需要修改为循环处理所有字面量数据块:

// ... 原代码中处理message的部分
if (message instanceof PGPLiteralData) {
    int fileCounter = 1;
    do {
        PGPLiteralData ld = (PGPLiteralData) message;
        String outFileName = ld.getFileName();
        // 处理默认文件名,给多段内容添加序号区分
        if (outFileName.length() == 0) {
            outFileName = defaultFileName + "_" + fileCounter++;
        }
        InputStream unc = ld.getInputStream();
        OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));
        Streams.pipeAll(unc, fOut);
        fOut.close();
        // 读取下一个内容块
        message = pgpFact.nextObject();
    } while (message instanceof PGPLiteralData);
} else if (message instanceof PGPOnePassSignatureList) {
    throw new PGPException("encrypted message contains a signed message - not literal data.");
} else {
    throw new PGPException("message is not a simple encrypted file - type unknown.");
}
// ...

这样修改后,解密时会为每段内容生成一个带序号的文件,你也可以调整代码将所有内容输出到同一个文件中。

内容的提问来源于stack exchange,提问作者manas ranjan Pradhan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:04:49