我已经尝试了好几个星期,使用bouncycastle和java来重现一些openssl命令。
在跟踪了许多示例并尝试了Stackoverflow的许多示例之后,我仍然无法使其正常工作,这就是为什么我现在寻求帮助。
我必须重现的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-type = signed-data; 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/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的缓冲区小得多。
有人知道原因吗?
答案 0 :(得分:1)
在签名方面,您与benchmark
#Unit: milliseconds
# expr min lq mean median uq max neval
# akrun 64.32350 66.99177 73.61685 71.15608 78.79612 104.99161 30
# markus 51.65092 53.01034 59.80802 58.48310 64.76143 78.35348 30
# A_Stam 1331.52882 1379.70371 1470.31044 1407.89861 1548.28011 1896.22913 30
十分接近,除了
它会处理多部分的数据,而org.bouncycastle.mail.smime.examples.CreateSignedMultipartMail
不会这样做;从openssl smime
开始
它会进行分段的 signing ,也就是透明签名,CreateSignedMail
也默认使用,但是openssl smime
会将其更改为嵌入式aka封装
它包括完整的证书链,但是一个自生成的证书链,长度只有2,而几乎所有“真实”证书都更长,而默认情况下,openssl仅包含签名者证书
默认情况下,它使用一些不同于openssl的签名属性
对于加密(或更确切地说是包围)-nodetach
,尽管名称根本不执行SMIME,但它执行CMS(最初仍称为PKCS7)。 Bouncy使用Java的全部OO优点将非常相似但不相同的CMS和SMIME放入相关但不相同的不同类中,因此您需要CMS类。
将这些组合在一起(加上最小的测试工具),我向您介绍:
openssl smime -outform der
打开,“有人知道原因吗?”
// 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);
小于内容?请参见the javadoc-将CMSSignedData signedData = signGen.generate(content, false);
byte[] signeddata = signedData.getEncoded();
(第二个参数)设置为encapsulate
,您告诉它不包括签名中的内容(更确切地说是SignedData),并按您的要求进行。