Bouncycastle和PKCS#1 v2.1,使用RSASSA-PSS进行签名并使用带有RSAES-OAEP的AES CBC进行加密

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bouncycastle和PKCS#1 v2.1,使用RSASSA-PSS进行签名并使用带有RSAES-OAEP的AES CBC进行加密相关的知识,希望对你有一定的参考价值。

在这个图书馆度过了无数个小时之后,我仍然无法让它发挥作用。

我想发送带有充气城堡库的smime消息,用RSASSA-PSS签名,用AES加密,其中密钥传输应该是RSAES-OAEP,所有P1#v2.1

签名者首先,这就是它的创建方式:

SMIMESignedGenerator gen = new SMIMESignedGenerator();
            SignerInfoGenerator signer
            = new JcaSimpleSignerInfoGeneratorBuilder()
            .setProvider("BC")
            .build("SHA256withRSAAndMGF1", pk.getPrivateKey(), pk.getCertificate()
            );
gen.addSignerInfoGenerator(signer);
        gen.addCertificates(certStore);
        MimeMultipart mmp = gen.generate(message);

所以现在它应该签名,加密和使用OAEP填充:

    OutputEncryptor enc = new BcCMSContentEncryptorBuilder(CMSAlgorithm.AES192_CBC).build();
        SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator();

        for (X509Certificate nCert : certs) {
                RecipientInfoGenerator keyTransportRecipient = 
                new JceKeyTransRecipientInfoGenerator(nCert).setProvider("BC").
setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/OAEPWithSHA256AndMGF1Padding");
                gen.addRecipientInfoGenerator(keyTransportRecipient);
        }
                MimeBodyPart encryptedMimeBodyPart = gen.generate(message, enc);

我找不到合适的setAlgorithmMapping()描述,所以我尝试了以下组合:

.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/NONE/PKCS1Padding");
.setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/OAEPWithSHA256AndMGF1Padding");
.setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA56AndMGF1Padding");

顺便问一下,任何人都可以解释一下,这种模式到底意味着什么 - “RSA / ECB / OAEPWithSHA256AndMGF1Padding”?如果第一个参数是公钥算法,我是对的,第二个“ECB”我是ECB AES模式吗? (我也尝试了CBC模式,但没有得到这样的算法异常,也试过NONE)而最后一个(“OAEPWithSHA56AndMGF1Padding”)显然是OAEP p1#v2.1,我实际上想要它。

因此,此时应对消息进行签名和加密。当我现在检查我的邮箱(使用Thunderbird)时,它说:“Thunderbird无法解密此邮件”,“发件人使用您的一个数字证书将此邮件加密给您,但是Thunderbird无法找到此证书和相应的私钥“。

但是,当我与老签名者签约时

build("SHA256withRSAEncryption", pk.getPrivateKey(), pk.getCertificate()

并使用旧的密钥传输方案,这是

setProvider("BC").setAlgorithmMapping(PKCSObjectIdentifiers.rsaEncryption, "RSA/NONE/PKCS1Padding");

一切正常。显然我的自签x509证书不是问题,如果我在这里,请纠正我。

我还用Outlook测试了它(2013)

旧方案(SHA256withRSAEncryption签署+ PKCS1Padding密钥传输) - >一切都很好。

新方案(SHA256withRSAAndMGF1签名+ RSA / ECB / OAEPWithSHA256AndMGF1Padding) - >“底层安全系统无法找到您的数字身份证名称”错误。

在这一点上,我不知道究竟是什么错。这是我用openssl创建证书的方法:

openssl req -new -x509 -nodes -sha256 -days 365 -newkey rsa:2048 -out certificate.cer -keyout private.key -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -passin pass:mypass -utf8 -config _openssl.cfg -extensions v3_req
openssl pkcs12 -export -out certificate.pfx -name "testname" -inkey private.key -in certificate.cer
答案

我想我解决了你的问题。至少在我的情况下它是有效的。对于PKCSObjectIdentifiers.id_RSAES_OAEP的AlgorithmIdentifier,我添加了以下代码行:

pubilc AlgorithmIdentifier getAlgo() {

        JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
        OAEPParameterSpec oaepSpec = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), new PSource.PSpecified(new byte[]{1, 2, 3, 4, 5}));
    return paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepSpec);
}

使用此参数化AlgorithmIdentifier,您现在可以加密您的消息:

AlgorithmIdentifier algo = getAlgo();
    SMIMEEnvelopedGenerator encrypter = new SMIMEEnvelopedGenerator();
    RecipientInfoGenerator keyTransportRecipient = 
                            new JceKeyTransRecipientInfoGenerator(cert).setProvider("BC").setAlgorithmMapping(PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA/ECB/OAEPWithSHA256AndMGF1Padding");

encrypter.generate(bodyPart, new JceCMSContentEncryptorBuilder(algo).setProvider("BC").build());                            encrypter.addRecipientInfoGenerator(keyTransportRecipient);

您在签署问题上取得了成功吗?就我而言,Outlook表示签名无效。

另一答案

我认为问题是大多数S / MIME客户端不支持RSASSA-PSS。我发现支持验证S / MIME RSASSA-PSS签名的唯一工具(BC除外)是openssl的最新版本。

根据openssl文档,这需要openssl> = 1.1.0。

openssl cms -verify -in email.eml -CAfile root.pem

这仅适用于openssl cms命令,而不适用于openssl smime命令。

以上是关于Bouncycastle和PKCS#1 v2.1,使用RSASSA-PSS进行签名并使用带有RSAES-OAEP的AES CBC进行加密的主要内容,如果未能解决你的问题,请参考以下文章

无法使用java中的pkcs#7和bouncyCastle签署zip文件

BouncyCastle 密钥转换 - Java pkcs1格式,pkcs8格式互转

找不到类 org.bouncycastle.cms.CMSSignedData

BouncyCastle 未定义长度 ASN1

在 Java 中生成 PKCS#1 格式的 RSA 密钥

读取pkcs12证书信息