无法使用 BouncyCastle 重现 openssl 命令
Posted
技术标签:
【中文标题】无法使用 BouncyCastle 重现 openssl 命令【英文标题】:Can't reproduce openssl command with BouncyCastle 【发布时间】:2019-01-15 14:00:17 【问题描述】:我已经尝试了几个星期来使用 bouncycastle 和 java 重现一些 openssl 命令。
在跟踪了大量示例并尝试了 *** 中的大量示例之后,我仍然无法使其工作,这就是我现在寻求帮助的原因。
我必须重现的 openssl 命令是:
openssl smime -sign -in fileToSign.eml -out signedFile.step2 -passin pass:« password» -binary -nodetach -signer myprivatecert.pem -certfile mypubliccert.pem
第一个命令需要 3 个文件,要签名的文件、私有证书和公共证书。
它返回一个看起来像这样的文件:
MIME 版本:1.0 内容处置:附件; filename="smime.p7m" 内容类型:application/x-pkcs7-mime; smime 类型=签名数据; name="smime.p7m" 内容传输编码: base64
MIJAYAYJKoZIhvcNAQcCoIJAUTCCQE0CAQExDzANBglghkgBZQMEAgEFADCCNTUG CSqGSIb3DQEHAaCCNSYEgjUiQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7 CmJvdW5kYXJ5PSItLS0tPUxPR0lQT0xfTUlGXzE1NDY4NTAwNDc4MTYiCi0tLS0t LT1MT0dJUE9MX01JRl8xNTQ2ODUwMDQ3ODE2DQpDb250ZW50LVR5cGU6IHRleHQv WE1MOw0KbmFtZT0iUERBX1A5MDAxMjZfMDA1XzIwMTkwMTA3LjA5MzIwMF8wMDAw MV9JTklULnhtbCI7IGZpbGVuYW1lPSJQREFfUDkwMDEyNl8wMDVfMjAxOTAxMDcu MDkzMjAwXzAwMDAxX0lOSVQueG1sIg0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGlu ZzogYmFzZTY0DQoNClBEOTRiV3dnZG1WeWMybHZiajBpTVM0d0lpQmxibU52Wkds dVp6MGlWVlJHTFRnaVB6NDhUVWxHVmtGUFNXNW1iMGx1YVhScFlXeGwNClBnbzhT VzVtYjNNK0NqeFdaWEp6YVc5dVBqSXVPVHd2Vm1WeWMybHZiajRLUEVodmNtOWtZ WFJsUGpJd01Ua3RNREV0TURkVU1EazYNCk16UTZNRGM4TDBodmNtOWtZWFJsUGdv OFUyRnBjMmxsU0c5eWIyUmhkR1UrTWpBeE9TMHdNUzB3TjFRd09Ub3pNam93TUR3...
我必须使用的第二个命令是:
openssl smime -encrypt -in signedFile.step2 -out encryptedFile.P7M -outform DER -binary anotherpubliccertificate.pub.pem
此命令需要 2 个文件,由上一个命令签名的文件和一个公共证书,与上一个命令中使用的不同。
这会返回一个二进制文件,一个从第 2 步生成的加密文件。
我在互联网上找到的任何示例都帮助我获得了一个看起来像以前的文件的文件,甚至不接近。
希望有人能帮忙
编辑 到目前为止,我尝试或参考的一些示例
sign file with bouncy castle in java -> 这返回了一个与 openssl 生成的签名文件不对应的签名文件
AES encrypt/decrypt with Bouncy Castle provider -> 同样,这不起作用,结果与我使用 openssl 生成的加密文件不对应
https://studylibfr.com/doc/3898805/cryptographie-avec-bouncy-castle---zenk -> 一直在关注整个教程,没有得到预期的结果
X509 RSA bouncy castle sign and verify plain text in Java -> 签名文件也不对应
https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/CreateSignedMultipartMail.java -> 这个类生成的东西和我想要得到的东西很相似,但我无法测试它的有效性,因为我必须对其进行加密,但仍然无法进行加密
https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/ReadSignedMail.java -> 和上一课一样
https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/SendSignedAndEncryptedMail.java -> 这种加密方法返回的结果与 openssl 不同,所以它不起作用
当然,我已经尝试继续研究 bouncycastle 中的这些示例类,但没有成功。
任何帮助将不胜感激
编辑 2 以下问题Sign and encrypt a file using S/MIME 的答案返回一个Base64 编码文件,该文件可能与我使用openssl 生成的文件相对应。但问题是我的入口文件大约25kb,生成的签名文件只有3kb,我不明白为什么,我注意到在这一行:
CMSTypedData content = new CMSProcessableByteArray(buffer);
CMSSignedData signedData = signGen.generate(content, false);
byte[] signeddata = signedData.getEncoded();
getEncoded() 方法返回的字节数组比我发送到 CMSSignedData 的缓冲区小得多。
有人知道原因吗?
【问题讨论】:
将二进制格式解释为文本是愚蠢的;查找 DER 的含义。 我知道 DER 是什么意思,谢谢,这并不能帮助我理解如何使文件看起来相似。我写了这些字符作为它的外观示例 我猜这就是人类发明十六进制的原因。如果您了解 DER,那么您不会发布对它的 UTF-8 解码。零序先生。对于这类问题,您应该发布您迄今为止开发的代码。 正如我上面的问题所说,我尝试了很多样本,字面意思是这么多,我不能只发布我所做的一切,因为我尝试的一切都没有返回我必须得到的结果.我问这个问题是希望有人能得到这个结果,而不是展示我尝试过和失败的一切,但我会编辑我的问题并添加一些我尝试过的例子 【参考方案1】:对于签名,你和org.bouncycastle.mail.smime.examples.CreateSignedMultipartMail
关系很密切,除了
它处理多部分数据,而openssl smime
不这样做;从CreateSignedMail
开始
它执行多部分签名,又名明确签名,openssl smime
也默认使用,但-nodetach
将其更改为嵌入式,即封装
它包括一个完整的证书链,但是一个长度仅为 2 的自行生成的证书链,而几乎所有“真实”证书都更长,而默认情况下,openssl 仅包括签名者证书
默认情况下它使用一些不同于openssl的签名属性
对于加密(或更准确地说是封装)openssl smime -outform der
,尽管名称根本不做 SMIME,但它做 CMS(最初也称为 PKCS7)。 Bouncy 充分利用 Java 的 OO 优点将非常相似但不相同的 CMS 和 SMIME 放入相关但不相同的不同类中,因此您需要 CMS 类。
把这些放在一起(加上一个最小的测试工具)我呈现给你:
// for test, (own) signing key+certchain and (peer) encryption cert in file
KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream(args[0]),args[1].toCharArray());
PrivateKey signkey = (PrivateKey) ks.getKey(args[2], args[1].toCharArray());
Certificate[] signcert = ks.getCertificateChain(args[2]);
Certificate encrcert = ks.getCertificate(args[3]);
// and data in file
byte[] data = Files.readAllBytes(new File(args[4]).toPath());
// adapted from org.bouncycastle.mail.smime.examples.CreateSignedMail
// OpenSSL uses this rather silly capability list; may not be needed
SMIMECapabilityVector caps = new SMIMECapabilityVector();
caps.addCapability(SMIMECapability.aES256_CBC);
caps.addCapability(SMIMECapability.aES192_CBC);
caps.addCapability(SMIMECapability.aES128_CBC);
caps.addCapability(SMIMECapability.dES_EDE3_CBC);
caps.addCapability(SMIMECapability.rC2_CBC, 128);
caps.addCapability(SMIMECapability.rC2_CBC, 64);
caps.addCapability(SMIMECapability.dES_CBC);
caps.addCapability(SMIMECapability.rC2_CBC, 40);
ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
signedAttrs.add(new SMIMECapabilitiesAttribute(caps));
// Bouncy default adds RFC6211 in addition to standard ctype, stime, mdgst
// and changing this is complicated; recipient _should_ ignore unneeded attr
SMIMESignedGenerator gen = new SMIMESignedGenerator();
gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder()//.setProvider("BC") not needed
.setSignedAttributeGenerator(new AttributeTable(signedAttrs))
.build("SHA1withRSA", signkey, (X509Certificate) signcert[0]) );
// change sigalg if key not RSA and/or want better hash
// OpenSSL by default includes only signer cert; recipient may want more
gen.addCertificates(new JcaCertStore (Arrays.asList (new Certificate[]signcert[0]) ));
MimeBodyPart msg = new MimeBodyPart();
msg.setText(new String(data, "ISO-8859-1")); // OpenSSL doesn't know charsets
ByteArrayOutputStream temp = new ByteArrayOutputStream();
gen.generateEncapsulated(msg).writeTo(temp); // OpenSSL -nodetach is encapsulated
// Bouncy uses BER here (unlike OpenSSL DER)
// and I don't see a simple way to change it but it _should_ not matter
byte[] signedblob = temp.toByteArray();
// now CMS (not SMIME) enveloping
CMSEnvelopedDataGenerator edgen = new CMSEnvelopedDataGenerator();
edgen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator((X509Certificate) encrcert));
CMSEnvelopedData edmsg = edgen.generate( new CMSProcessableByteArray(signedblob),
new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).build() );
byte[] encrblob = edmsg.toASN1Structure().getEncoded(ASN1Encoding.DER); // OpenSSL is DER though std doesn't require it
// for test, write to a file
Files.write(new File(args[5]).toPath(), encrblob);
打开,“有人知道原因吗”
CMSSignedData signedData = signGen.generate(content, false);
byte[] signeddata = signedData.getEncoded();
小于内容?请参阅the javadoc -- 将encapsulate
(第二个参数)设置为false
,您告诉它不在签名中包含内容(更确切地说是SignedData),它按照您的要求执行了.
【讨论】:
您好,对不起,我的回答迟了,看来,感谢您的回答,现在加密问题已经解决了!非常感谢你,你救了我的命现在签名,我还不能尝试,但我注意到 smime 文件的标题与 openssl 生成的标题完全不同,当然这可能不是重要,但这是我注意到的: - OpenSSL 的内容类型属性是:application/x-pkcs7-mime 和 BouncyCastle:application/pkcs7-mime 我希望你能帮我解决这个问题,再次感谢你帮助以上是关于无法使用 BouncyCastle 重现 openssl 命令的主要内容,如果未能解决你的问题,请参考以下文章
使用 mbedtls 生成的 RSA 签名,无法使用 C# (bouncycastle) 应用程序进行验证
使用 BouncyCastle 生成的证书作为服务器进行身份验证时出现“无法识别提供给包的凭据”错误
无法使用java中的pkcs#7和bouncyCastle签署zip文件
无法将“Org.BouncyCastle.Asn1.DerSequence”类型的对象转换为“Org.BouncyCastle.Asn1.DerInteger”类型
向证书请求添加属性,java + bouncycastle 1.48
Flutter 错误:无法下载 bcprov-jdk15on.jar (org.bouncycastle:bcprov-jdk15on:1.56)