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格式互转