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

关于创建MANIFEST-INF/CERT.RSA及基于BouncyCastle重实现JAR/APK V1签名writeSignatureBlock方法的技术求助

关于创建MANIFEST-INF/CERT.RSA及基于BouncyCastle重实现JAR/APK V1签名writeSignatureBlock方法的技术求助

我太懂你这种困境了——高版本JDK里那些老旧的PKCS7、SignerInfo类要么被标记为废弃,要么直接从核心库移除了,想用BouncyCastle重写这个V1签名的writeSignatureBlock方法确实得费点功夫。我之前也踩过类似的坑,给你整理一套可行的实现方案:

首先,你得先引入BouncyCastle的依赖(如果是Maven项目的话):

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.70</version> <!-- 建议用最新稳定版 -->
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
</dependency>

然后,重写writeSignatureBlock方法。核心思路是用BouncyCastle的CMS(Cryptographic Message Syntax)API来替代原来的JDK内置PKCS7实现,步骤和你原来的代码逻辑完全对应:

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

import java.io.OutputStream;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;

private static void writeSignatureBlock(X509Certificate publicKey, PrivateKey privateKey, OutputStream out) throws Exception {
    // 首先注册BouncyCastle安全提供者,这一步绝对不能少,不然会找不到对应算法
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
        Security.addProvider(new BouncyCastleProvider());
    }

    // 1. 创建签名器,对应原代码中signature.sign()的核心逻辑
    ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1withRSA")
            .setProvider(BouncyCastleProvider.PROVIDER_NAME)
            .build(privateKey);

    // 2. 构建SignerInfo实例,和原代码的SignerInfo初始化逻辑对齐
    JcaSignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(
            new JcaDigestCalculatorProviderBuilder()
                    .setProvider(BouncyCastleProvider.PROVIDER_NAME)
                    .build());
    // 设置直接签名模式,对应原代码中ContentInfo.DATA_OID为null的场景
    signerInfoGeneratorBuilder.setDirectSignature(true);

    // 3. 构建PKCS7结构(BouncyCastle里叫CMSSignedData)
    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    generator.addSignerInfoGenerator(
            signerInfoGeneratorBuilder.build(contentSigner, publicKey));
    generator.addCertificate(publicKey);

    // 原代码中没有传入实际数据,所以这里用空字节数组模拟
    CMSSignedData signedData = generator.generate(
            new CMSProcessableByteArray(new byte[0]), false);

    // 4. 将PKCS7结构编码输出到流,对应原代码的pkcs7.encodeSignedData(out)
    signedData.getEncoded().writeTo(out);
}

这里有几个关键细节要划重点:

  • 原代码中ContentInfo传入了DATA_OID但内容为null,所以我们用CMSProcessableByteArray(new byte[0])模拟这个逻辑,同时调用generate时传false表示不封装实际数据
  • 必须提前注册BouncyCastle提供者,否则会出现「算法找不到」的异常
  • 原代码用的是SHA1哈希+RSA签名的组合,对应BouncyCastle里的SHA1withRSA算法标识符
  • 我把原方法里的Signature参数换成了PrivateKey,因为原代码的signature本质是用私钥初始化的,直接传私钥逻辑更清晰(如果你一定要保留Signature参数,也可以从signature中提取私钥,但步骤会冗余一些)

如果你还需要补全V1签名的完整流程(比如生成MANIFEST.MF、CERT.SF文件),可以参考BouncyCastle的CMS官方文档,但针对你问的writeSignatureBlock重实现,上面的代码应该能完美替代你注释掉的原逻辑。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:19:28