【问题标题】:Retrieving CMSSignedData from ASN.1 encoding in Bouncy Castle从 Bouncy Castle 中的 ASN.1 编码中检索 CMSSignedData
【发布时间】:2017-06-22 15:56:30
【问题描述】:

在以下代码中,我使用 Bouncy Castle 签署了一条消息:

import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
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 org.bouncycastle.util.encoders.Base64;

import java.io.FileInputStream;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;

public class Sign {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        String certPath = "certPath";
        FileInputStream inPublic = new FileInputStream(certPath);
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        X509Certificate cert = (X509Certificate) factory.generateCertificate(inPublic);


        String keyPrivatePath = "keyPath";
        Path path = Paths.get(keyPrivatePath);
        Files.readAllBytes(Paths.get(keyPrivatePath));
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Files.readAllBytes(Paths.get(keyPrivatePath)));
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = kf.generatePrivate(spec);

        CMSProcessableByteArray msg = new CMSProcessableByteArray("My message".getBytes());
        CMSSignedDataGenerator sGen = new CMSSignedDataGenerator();

        ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privateKey);
        sGen.addSignerInfoGenerator(
                new JcaSignerInfoGeneratorBuilder(
                        new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()
                ).build(sha1Signer, cert)
        );

        CMSSignedData sd = sGen.generate(msg);

        CMSTypedData cmsBytes = new CMSProcessableByteArray(sd.getEncoded());
        // How to reconstruct a CMSSignedData from cmsBytes again?
        byte[] bytes = (byte[]) cmsBytes.getContent();
        CMSSignedData retrieved = new CMSSignedData(bytes);
        System.out.println(retrieved.getSignedContent()); // Doesn't work, is null
    }
}

我的问题是如何仅使用此对象的 ASN.1 编码的字节数组来检索原始CMSSignedData(想读取原始消息并进行验证)。

我问这个的原因是我想解密某个加密和签名的消息。我能够解密此消息,但它会生成一个 ASN.1 编码字节数组(它确实对应于我的原始消息),但我无法进一步处理此解密消息。

【问题讨论】:

    标签: java bouncycastle asn.1 pkcs#7


    【解决方案1】:

    您可以使用org.bouncycastle.asn1.cms.ContentInfoorg.bouncycastle.asn1.ASN1Sequence 类:

    CMSTypedData cmsBytes = new CMSProcessableByteArray(sd.getEncoded());
    byte[] bytes = (byte[]) cmsBytes.getContent();
    
    // reconstruct CMSSignedData from the byte array
    ContentInfo ci = ContentInfo.getInstance(ASN1Sequence.fromByteArray(bytes));
    CMSSignedData sig = new CMSSignedData(ci);
    

    另外请注意,您必须创建一个CMSSignedData,其内容封装在签名中,因此您必须更改此内容:

    CMSSignedData sd = sGen.generate(msg);
    

    到这里:

    CMSSignedData sd = sGen.generate(msg, true);
    

    【讨论】:

    • 不幸的是,这不起作用:(在这种情况下,sig.getSignedContent() 产生 null,而不是我输入的消息的 CMSProcessableByteArray...
    • 您使用的是什么版本?我正在使用 BouncyCastle 1.57 和 Java 1.7
    • bouncyCastle 1.57 和 Java 1.8。它应该适用于 Java 1.7 吗?
    • 您是否检查过原始CMSSignedData 中的getSignedContent 是否为空?
    • 非常感谢雨果!我非常感谢它:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多