如何为CMS扩展/添加Bouncycastle摘要算法?

时间:2017-11-03 13:08:24

标签: java cryptography bouncycastle

使用Java我希望使用RSA对给定的byte[] hash进行加密签名,并以Cryptographic Message Syntax (CMS)格式返回byte[] signature

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

遗憾的是,我无法更改输入和所需的输出格式,因此我需要扩展/添加到现有的BC算法,以便我可以使用NONEwithRSA而不是所有其他现有(例如{{1} }})。我该怎么做呢?我没有在BC文档中找到任何示例。

我想要的用法与此类似

SHA256withRSA

到目前为止我尝试了什么

  • 使用"复制"为JCA添加我自己的提供程序一堆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(); } 基本上返回SHA256withRSA而不是NoneDigest。但这似乎是非常错误的。
  • 将我自己的算法添加到带有SHA256Digest的BC,这似乎不起作用(找不到算法)

我希望得到一些建议和指导(如果可能的话)"正确的方式" 。感谢。

1 个答案:

答案 0 :(得分:1)

“NoneWithRSA”是RSA数字签名,不添加摘要算法的OID。加密提供程序也不进行摘要。基本上它是带有私钥的PKCS#1_v15加密。

您可以在此OpenJDK测试https://github.com/ddopson/openjdk-test/blob/master/java/security/Signature/NONEwithRSA.java

中查看其工作原理

由于Bouncycastle似乎不支持它,我认为您可以使用默认提供商提供自己的ContentSigner实施,而不是使用JcaContentSignerBuilder

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

  

A.2.4 RSASSA-PKCS1-v1_5

     

RSASSA-PKCS1-v1_5的对象标识符应为其中之一      以下。 OID的选择取决于散列的选择      算法:MD2,MD5,SHA-1,SHA-256,SHA-384或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;
        }
    }
}

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