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

如何用Bouncy Castle验证PGP解密后的ASCII-Armored数据及相关疑问

PGP与Bouncy Castle签名验证疑问解答

核心问题解答

1. ASCII-Armored数据包含的内容

你的签名代码生成的ASCII-Armored数据不包含原始待签名的完整数据,仅包含两部分PGP签名相关数据:

  • OnePass签名头(由generateOnePassVersion(false)生成):包含签名算法、哈希算法等元信息,用于提前告知验证方后续签名的验证规则
  • 最终签名值(由generate()生成):是原始数据哈希值经过私钥加密后的结果(并非单纯的哈希摘要,包含摘要算法标识等额外信息)

2. 提取数据与签名的情况(不适用当前场景)

由于你的代码未将原始数据写入输出流,因此当前的ASCII-Armored数据中没有原始内容,不存在提取原始数据的可能。如果是包含原始数据的PGP签名包(比如同时输出原始数据和签名),可以通过PGPObjectFactory解析流,分离出原始数据对象和签名对象。

3. 验证时的操作方式

因为签名数据中不包含原始内容,验证时必须手动提供原始数据,核心逻辑是:将签名数据解码为二进制流后,解析出签名相关元信息,再用原始数据更新验证器,最终完成签名有效性校验。

无需ASCII-Armored的签名与验证方式

ASCII-Armored只是PGP数据的文本编码格式,用于适配文本传输场景。直接使用二进制格式更高效,实现方式如下:

签名代码(二进制版)

private ByteArrayOutputStream signDataBinary(byte[] data, PGPPrivateKey privateKey, int hashAlgo) throws PGPException, IOException {
    JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(PGPPublicKey.RSA_GENERAL, hashAlgo)
            .setProvider(BouncyCastleProvider.PROVIDER_NAME);
    PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
    signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey);
    
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
    BCPGOutputStream bOut = new BCPGOutputStream(byteOut);

    signatureGenerator.generateOnePassVersion(false).encode(bOut);
    signatureGenerator.update(data);
    signatureGenerator.generate().encode(bOut);

    bOut.close();
    return byteOut;
}

验证说明

验证时直接读取二进制签名流即可,无需通过ArmoredInputStream解码ASCII-Armored格式,其余验证逻辑与文本格式一致。

OnePassSignatureList的验证原理与代码示例

工作原理

OnePass签名的设计目的是支持流式验证:验证方不需要先完整接收原始数据和签名,而是可以在读取原始数据的同时,用OnePass签名头初始化验证器,逐步更新验证状态,最后用最终的签名值确认结果。这种方式适合处理大文件或流式数据,无需将全部数据加载到内存。

验证代码示例

public boolean verifySignature(byte[] originalData, byte[] armoredSignatureData, PGPPublicKey publicKey) throws PGPException, IOException {
    // 解码ASCII-Armored签名数据
    ArmoredInputStream armoredIn = new ArmoredInputStream(new ByteArrayInputStream(armoredSignatureData));
    PGPObjectFactory factory = new PGPObjectFactory(armoredIn, new JcaKeyFingerprintCalculator());
    
    // 读取OnePass签名列表并初始化验证器
    OnePassSignatureList onePassSigList = (OnePassSignatureList) factory.nextObject();
    OnePassSignature onePassSig = onePassSigList.get(0);
    onePassSig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(BouncyCastleProvider.PROVIDER_NAME), publicKey);
    
    // 用原始数据更新验证器(支持分块调用update处理大文件)
    onePassSig.update(originalData);
    
    // 读取最终签名并完成验证
    PGPSignatureList sigList = (PGPSignatureList) factory.nextObject();
    PGPSignature signature = sigList.get(0);
    
    return onePassSig.verify(signature);
}

代码说明:

  1. 先从签名流中解析OnePassSignatureList,用公钥初始化验证器
  2. 将原始数据输入到验证器的update方法(处理大文件时可逐段读取并调用)
  3. 读取最终的PGPSignature,调用verify方法确认签名与流式计算结果是否一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 19:42:28