在这个图书馆度过了无数个小时后,我仍然无法正常工作。
我想发送带有充气城堡库的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)
对其进行了测试旧方案(SHA256withRSAE加密签名+ 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
答案 0 :(得分:1)
我想我解决了你的问题。至少在我的情况下它是有效的。 对于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表示签名无效。
答案 1 :(得分:1)
我认为问题是大多数S / MIME客户端不支持 RSASSA-PSS。唯一的工具(除了BC)我发现支持验证 S / MIME RSASSA-PSS签名是openssl的最新版本。
根据openssl文档,这需要openssl> = 1.1.0。
openssl cms -verify -in email.eml -CAfile root.pem
这仅适用于openssl cms命令,而不适用于openssl smime命令。
答案 2 :(得分:0)
将RSA-OAEP的AlgorithmIdentifier授予OutputEncryptor是错误的方法。至少对我来说,它将导致如下错误:
... no such algorithm: 1.2.840.113549.1.1.7 for provider BC
如果要使用AES和RSA-OAEP,则必须将AES分配给OutputEncryptor
(谁负责对称加密)
和RSA-OAEP到RecipientInfoGenerator
(分别负责密钥加密和非对称加密)。
代码如下:
(OAEPParameterSpec
的定义已经在此处的上一篇文章中得到了正确解释)。
// Note that at JcaAlgorithmParametersConverter is available since BC 1.50.
JcaAlgorithmParametersConverter paramsConverter = new JcaAlgorithmParametersConverter();
OAEPParameterSpec oaepParameters = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec(
"SHA-256"), PSource.PSpecified.DEFAULT);
AlgorithmIdentifier idRsaOaep = paramsConverter.getAlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, oaepParameters);
SMIMEEnvelopedGenerator encryptor = new SMIMEEnvelopedGenerator();
// Assign OAEPParameterSpec and an instance of X509Certificate to the RecipientInfoGenerator.
// prov is an instance of BouncyCastleProvider.
encryptor.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(certificate, idRsaOaep)
.setProvider(prov));
// Use an OutputEncryptor with AES.
OutputEncryptor outputEncryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC)
.setProvider(prov)
.build();
// Do encryption (were plaintextMsg is a MimeMessage instance).
MimeBodyPart payload = encryptor.generate(plaintextMsg, outputEncryptor);