如何extend/add一个用于CMS的Bouncycastle摘要算法?

How to extend/add a Bouncycastle digest algorithm for CMS?

使用 Java 我想使用 RSA 和 return byte[] signatureCryptographic Message Syntax (CMS) 格式对给定的 byte[] hash 进行加密签名。

我为此目的使用 Bouncycastle Java API (BC) 并面临 NONEwithRSA 签名类型不存在的问题。 (java.lang.IllegalArgumentException: Unknown signature type requested: NONEWITHRSA).

不幸的是,我无法更改输入或所需的输出格式,因此我需要 extend/add 现有的 BC 算法,以便我可以使用 NONEwithRSA 而不是所有其他现有的 (例如 SHA256withRSA)。我该怎么做呢?我没有在 BC 文档中找到任何示例。

我想要的用法与此类似

byte[] doSigningCMS(byte[] data, X509Certificate cert, PrivateKey key) throws Exception {

    CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
    CMSTypedData content = new CMSProcessableByteArray(data);

    ContentSigner signer = new JcaContentSignerBuilder("NONEwithRSA").build(key);

    DigestCalculatorProvider dcp = new JcaDigestCalculatorProviderBuilder().build();

    signGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(dcp).build(signer, cert));

    return signGen.generate(content, false).getEncoded();
}

到目前为止我尝试了什么

我希望得到一些建议和指导来做到这一点(如果可能的话)"the right way"。谢谢。

"NoneWithRSA"是不加摘要算法OID的RSA数字签名。密码提供者也不制作摘要。基本上它是使用私钥的 PKCS#1_v15 加密。

您可以在这个 OpenJDK 测试中看到它是如何工作的https://github.com/ddopson/openjdk-test/blob/master/java/security/Signature/NONEwithRSA.java

由于 Bouncycastle 似乎不支持它,我认为您可以使用默认提供程序而不是使用 JcaContentSignerBuilder

来提供您自己的 ContentSigner 实现

假设输入数据已经被散列,所以如果你做的是PKCS#1签名,我想你需要提供签名算法。查看 RFC3477 它取决于所使用的哈希算法。

A.2.4 RSASSA-PKCS1-v1_5

The object identifier for RSASSA-PKCS1-v1_5 shall be one of the following. The choice of OID depends on the choice of hash algorithm: MD2, MD5, SHA-1, SHA-256, SHA-384, or SHA-512.


String sigAlgo = "SHA256WithRSAEncryption"; // "SHA256WithRSAEncryption" for SHA256, "SHA1WithRSAEncryption" for SHA1, etc.
ContentSigner signer = new CustomContentSigner(key, sigAlgo );

public class CustomContentSigner implements ContentSigner {

    private AlgorithmIdentifier algorithmIdentifier;
    private Signature signature;
    private ByteArrayOutputStream outputStream;

    public CustomContentSigner(PrivateKey privateKey, String sigAlgo) {
        //Utils.throwIfNull(privateKey, sigAlgo);
       this.algorithmIdentifier = new DefaultSignatureAlgorithmIdentifierFinder().find(sigAlgo);

        try {
            this.outputStream = new ByteArrayOutputStream();
            this.signature = Signature.getInstance("NONEwithRSA");
            this.signature.initSign(privateKey);
        } catch (GeneralSecurityException gse) {
            throw new IllegalArgumentException(gse.getMessage());
        }
    }

    @Override
    public AlgorithmIdentifier getAlgorithmIdentifier() {
        return algorithmIdentifier;
    }

    @Override
    public OutputStream getOutputStream() {
        return outputStream;
    }

    @Override
    public byte[] getSignature() {
        try {
            signature.update(outputStream.toByteArray());
            return signature.sign();
        } catch (GeneralSecurityException gse) {
            gse.printStackTrace();
            return null;
        }
    }
}

免责声明:我不知道它是否有效,但您可以尝试一下