PKCS7和" NONEwithRSA"签名

时间:2018-03-23 15:06:31

标签: java rsa bouncycastle sha256 pkcs#7

我需要计算一些数据签名,使用未封装的pkcs7与sha256和RSA。 原始内容没问题,使用:

public byte[] signRawContent(final byte[] content)
    throws CMSException, IOException, OperatorCreationException, CertificateEncodingException {

    // Create generator of pkcs7-signature message
    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").setProvider("BC").build(privateKey);
    generator.addSignerInfoGenerator(
        new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(signer, certificate));
    generator.addCertificate(new X509CertificateHolder(certificate.getEncoded()));

    CMSTypedData cmsTypedData = new CMSProcessableByteArray(content);
    CMSSignedData cmsSignedData = generator.generate(cmsTypedData, false);
    return cmsSignedData.getEncoded();
}

但我有另一个用户案例,我没有原始内容,只有它的哈希值(sha256) Bouncycastle不支持" NONEwithRSA"或者" RSA"对于pkcs7签名, 所以我尝试使用自定义ContentSigner,但没有得到相同的 带有原始内容版本的签名。

public byte[] signHash(final byte[] sha256) throws IOException,
    OperatorCreationException, CertificateEncodingException, CMSException {

    // Create generator of pkcs7-signature message
    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    // custom content signer to bypass hash
    ContentSigner signer = new ContentSigner() {
        @Override public AlgorithmIdentifier getAlgorithmIdentifier() {
            return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
        }

        @Override public OutputStream getOutputStream() {
            return new ByteArrayOutputStream();
        }

        @Override public byte[] getSignature() {
            try {
                Signature signer = Signature.getInstance("NONEwithRSA");
                signer.initSign(privateKey);
                signer.update(sha256);
                return signer.sign();
            } catch (Exception e){
            throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
            }
        }
    };

    generator.addSignerInfoGenerator(
        new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(signer, certificate));
    generator.addCertificate(new X509CertificateHolder(certificate.getEncoded()));

    CMSTypedData cmsTypedData = new CMSProcessableByteArray(sha256);
    CMSSignedData cmsSignedData = generator.generate(cmsTypedData, false);
    return cmsSignedData.getEncoded();
}

我甚至尝试重建内容摘要,没有运气

 // build digest
 MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
 messageDigest.update(sha256);
 byte[] outputDigest = messageDigest.digest();
 AlgorithmIdentifier sha256Aid = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
 DigestInfo di = new DigestInfo(sha256Aid, outputDigest);

 //sign SHA256 with RSA
 Signature rsaSignature = Signature.getInstance("RSA");
 rsaSignature.initSign(privateKey);
 byte[] encodedDigestInfo = di.toASN1Primitive().getEncoded();
 rsaSignature.update(encodedDigestInfo);
 return rsaSignature.sign();

那么有没有办法让pkcs7形成sha256? 感谢

1 个答案:

答案 0 :(得分:0)

找到了可行的解决方案:

private static final String SIGNATURE_ALGO = "SHA256WithRSA";

/**
 * Get the pkcs7-signature from a document hash (sha256Hex)
 *
 * @param contentSha256Hex
 *     the original document content hash (sha256Hex) to be signed
 * @return the pkcs7 signature
 *
 * note: see TestSha1WithRsaAndAttributeTable() in bouncycastle/test/src/cms/test/SignedDataTest.cs
 * */
public byte[] signSha256Hex(final String contentSha256Hex)
    throws CertificateEncodingException, IOException, OperatorCreationException, CMSException, DecoderException {

    byte[] hash = Hex.decodeHex(contentSha256Hex);

    /*
     * The trick is to manually set digest attribute with hash value,
     * then generate signature without content.
     */

    // CMS attributes
    ASN1EncodableVector v = new ASN1EncodableVector();
    v.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(hash)))); // set digest (sha256)

    return signCms_Sha256WithRsa(
        new CMSAbsentContent(),
        new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));

}

private byte[] signCms_Sha256WithRsa(CMSTypedData content, CMSAttributeTableGenerator signedAttributes)
    throws CMSException, IOException, CertificateEncodingException, OperatorCreationException {

    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();

    // content signer
    ContentSigner signer = new JcaContentSignerBuilder(SIGNATURE_ALGO).setProvider("BC").build(privateKey);
    generator.addSignerInfoGenerator(
        new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
            .setSignedAttributeGenerator(signedAttributes)
            .build(signer, certificate));

    // add certificate
    generator.addCertificate(new X509CertificateHolder(certificate.getEncoded()));

    // sign
    CMSSignedData cmsSignedData = generator.generate(content, false);
    return cmsSignedData.getEncoded();
}