- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在使用 BC 加密和签署用于 AS2 的 SMIME 消息。我们的代码适用于绝对古老的充气城堡版本 bcmail-1.4:125
。升级到更新的版本会导致消息的接收者(不是太古老的 Cyclone 服务器)无法验证消息。 (例如 maven 中最早的 v 也会导致此问题。这些是没有 API 更改的版本(例如 1.38)。
自从我们使用 JDK 1.7(和 1.8)以来,我一直在尝试将它更新到更新版本的 BC、java-mail 等。我已经将所有的充气城堡升级到 bcmail-jdk15on: 1.51
和 bcprov-jdk15on:1.51
,以及 java 邮件,并遵循 bcmail
包中的示例。但是,我仍然收到 Cyclone 的错误消息,提示 integrity-check-failed
。
我相当确定错误出在我的签名方式上。当我禁用签名并仅使用加密时,它会正确处理。此外,我可以正确地从远程服务器接收签名的响应并验证签名,这就是我获取错误消息的方式(从 MimeMultiPart 上的内容配置)。
senderKey
是一个 BCRSAPrivateCrtKey
senderCert
org.bouncycaSTLe.jcajce.provider.asymmetric.x509.X509CertificateObject
失败:当前代码是这样的,使用bcmail-jdk15on:1.51
& etc
SMIMESignedGenerator gen = new SMIMESignedGenerator();
gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder()
.setProvider("BC")
.build("SHA1withRSA", senderKey, senderCert));
// gen.addCertificates(new JcaCertStore(list(senderCert))); old v. doesn't add certs
MimeMultipart smime = gen.generate(part); // MimeBodyPart passed in to function
MimeBodyPart tmpBody = new MimeBodyPart();
tmpBody.setContent(signedData);
tmpBody.setHeader("Content-Type", signedData.getContentType()
以前的工作代码 看起来像这样并使用 bcmail-1.4:1.25
。升级到 1.3x 也会导致另一端在解密时失败(无论我在哪个 jdk 上运行,1.6 - 1.8)
MimeBodyPart body = new MimeBodyPart();
body.setDataHandler(new DataHandler(new ByteArrayDataSource(bytes[], contentType, null);));
SMIMESignedGenerator sGen = new SMIMESignedGenerator();
// SHA1 resolves to "1.3.14.3.2.26", FWIW
sGen.addSigner(senderKey, senderCert, getBouncyCastleAlgorithmId("SHA1"));
MimeMultipart signedData = sGen.generate(part, "BC");
// this is then encrypted & streamed, no issues there
通用设置代码
byte[] data = Files.readAllBytes(filePath);
MimeBodyPart part = new MimeBodyPart();
ByteArrayDataSource dataSource = new ByteArrayDataSource(data, "application/EDIFACT", null);
part.setDataHandler(new DataHandler(dataSource));
part.setHeader("Content-Transfer-Encoding", "8bit");
part.setHeader("Content-Type", "application/EDIFACT");
我感觉这与我添加(或操作)senderCert
的方式有关,它是本地应用程序的 X509。
更新
我通过删除证书使新代码与旧代码更加一致:
这是示例输出,FWIW。 []
中的文本是唯一发生变化的部分。
------=_Part_1_1448572667.1409621469842
Content-Type: application/EDIFACT
Content-Transfer-Encoding: 8bit
this is a test
------=_Part_1_1448572667.1409621469842
Content-Type: application/pkcs7-signature; name=smime.p7s; smime-type=signed-data
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
Content-Description: S/MIME Cryptographic Signature
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAMYIBpDCCAaAC
AQEwgZ4wgZAxCzAJBgNVBAYTAmNuMREwDwYDVQQIDAhzaGFuZ2hhaTESMBAGA1UEBwwJY2hhbmdu
aW5nMREwDwYDVQQKDAhwb3dlcmUyZTEOMAwGA1UECwwFaXRkZXYxEjAQBgNVBAMMCWFiLWNsaWVu
dDEjMCEGCSqGSIb3DQEJARYUYWItY2xpZW50QG15Q29ycC5jb20CCQClDAGwq37A/jAJBgUrDgMC
GgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTQwOTAyMDEz
M[TA5]WjAjBgkqhkiG9w0BCQQxFgQUG6KkoqPBvE7Kd9dB0eop/aUTya0wDQYJKoZIhvcNAQEBBQAE
gYB[h9N4maow9aoTQ8QBGgXEYE+xgXSmRPy+ufIsMpuS0Yys/1t3AfXSSI7WKgLMRKYXve8gdb4Gn
dqecHzkBwBq4hebt9YK+E30E6DpZpCwErsgDVaU/ExBA5gauPWneysy+s2bE5Y6pNZ7Qf3kGU5kI
UjlOF/LUNkCsgT5z//]5N6QAAAAAAAA==
------=_Part_1_1448572667.1409621469842--
最佳答案
经过大量的debug、dump文件等,证明了和digest计算有一定关系。在签名正文部分的特定位置是内容 MIC(摘要的 base64)。不知何故,这个值与另一方所做的不匹配......
一旦我知道了,并且在谷歌上又花了一些时间,我终于找到了 more information on sourceforge 来确认这一点。很有帮助,因为它提到了我的特定版本的 BC。引用:
The problem is that BC >= 1.27 will "canonicalize" all messages that are not sent with content-transfer-encoding binary.
What does this mean?
In the S/MIME rfc it says that all messages should be converted to a "canonical" form before computing the MIC. The "canonical" form for text messages is that EOL is indicated by CR, LF. The rfc's are silent on what the canonical form for other content types is. Many S/MIME implementations (e.g. openssl, Bouncy Castle after 1.27) incorrectly assume that the canonical form for all messages except those sent with content-transfer-encoding binary is that every LF should be preceeded by a CR.
So if a BC 1.25 used sends a message including bare LF characters then the MIC validation will fail if the message is received by an application using BC >= 1.27, or openssl smime, or many other S/MIME implementations.
OpenAS2 should be fixed to use content-transfer-encoding binary.
只有在 MIME 正文部分上设置编码时,这才有效。我已经通过执行 JCA 路由验证了相同的结果(在服务器上失败)手动,轻量级路线,还有CMS路线。
根据这些信息,我对发件人做了一个简单的更改....
MimeBodyPart part = //.. make mime body part from file
part.setHeader("Content-Transfer-Encoding", "binary");
有趣的是,改变任何与 SMIMESignedGenerator()
相关的东西似乎都没有效果:
gen = SMIMESignedGenerator("binary"); // nothing, even though the docs say to set this
对于任何感兴趣的人,我的最终签名函数如下所示:
SMIMESignedGenerator gen = new SMIMESignedGenerator();
SignerInfoGenerator sigGen = new JcaSimpleSignerInfoGeneratorBuilder()
.setProvider(BC)
.build("SHA1withRSA", senderKey, senderCert);
gen.addSignerInfoGenerator(sigGen);
MimeMultipart smime = gen.generate(part);
MimeBodyPart tmpBody = new MimeBodyPart();
tmpBody.setContent(smime);
tmpBody.setHeader("Content-Type", smime.getContentType());
return tmpBody;
原始文件只有一行:
this is a test
被签名的输入是这样的:
Content-Type: application/EDIFACT
Content-Transfer-Encoding: binary
this is a test
调试信息:
data bytes:
436F6E74656E742D547970653A206170706C69636174696F6E2F454449464143540D0
A436F6E74656E742D5472616E736665722D456E636F64696E673A2062696E6172790D
0A0D0A74686973206973206120746573740A
digest mic: {
"algorithmId": "1.3.14.3.2.26"
"digest bytes": "CEC2C6614A481DFDF45C801FD6F2A51BC53D3FDF"
"digest base64": "zsLGYUpIHf30XIAf1vKlG8U9P98="
}
Not 这不附加签名,或添加任何功能,并使用 v1 x509 证书。现在一切都恢复正常了,我可能会改变这些东西。
我真的希望所有这一切都更加透明......BC 在内部是间接的间接的,虽然我明白为什么。它在内部仍然比旧版本好。我不能说我没有找到很多示例,但是 BC 测试用例似乎不是最好的(例如,我找不到一个在之后根据预期摘要值进行验证的测试用例SMIME'ing。也许我错过了)
关于java - 使用较新版本的 Bouncy CaSTLe 时,接收方无法验证 SMIME,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25562613/
我有一个存储结构向量的应用程序。这些结构保存有关系统上每个 GPU 的信息,如内存和 giga-flop/s。每个系统上有不同数量的 GPU。 我有一个程序可以同时在多台机器上运行,我需要收集这些数据
我很好奇 MPI 中缺少此功能: MPI_Isendrecv( ... ); 即,非阻塞发送和接收,谁能告诉我其省略背后的基本原理? 最佳答案 我的看法是 MPI_SENDRECV存在是为了方便那些想
当我用以下方法监听TCP或UDP套接字时 ssize_t recv(int sockfd, void *buf, size_t len, int flags); 或者 ssize_t recvfrom
SUM:如何在 azure 事件网格中推迟事件触发或事件接收? 我设计的系统需要对低频对象状态(创建、启动、检查长时间启动状态、结束)使用react。它看起来像是事件处理的候选者。我想用azure函数
我正在 MPI 中实现一个程序,其中主进程(等级 = 0)应该能够接收来自其他进程的请求,这些进程要求只有根才知道的变量值。如果我按等级 0 进行 MPI_Recv(...),我必须指定向根发送请求的
我正在学习DX12,并在此过程中学习“旧版Win32”。 我在退出主循环时遇到问题,这似乎与我没有收到WM_CLOSE消息有关。 在C++,Windows 10控制台应用程序中。 #include
SUM:如何在 azure 事件网格中推迟事件触发或事件接收? 我设计的系统需要对低频对象状态(创建、启动、检查长时间启动状态、结束)使用react。它看起来像是事件处理的候选者。我想用azure函数
我想编写方法来通过号码发送短信并使用编辑文本字段中的文本。发送消息后,我想收到一些声音或其他东西来提醒我收到短信。我怎样才能做到这一点?先感谢您,狼。 最佳答案 这个网站似乎对两者都有很好的描述:ht
所以我正在用 Java 编写一个程序,在 DatagramSocket 和 DatagramPacket 的帮助下发送和接收数据。问题是,在我发送数据/接收数据之间的某个时间 - 我发送数据的程序中的
我是 Android 编程新手,我正在用 Java 编写一个应用程序,该应用程序可以打开相机拍照并保存。我通过 Intents 做到了,但看不到 onActivityResult 正在运行。 我已经在
我有一个套接字服务器和一个套接字客户端。客户端只有一个套接字。我必须使用线程在客户端发送/接收数据。 static int sock = -1; static std::mutex mutex; vo
我正在尝试使用 c 中的套接字实现 TCP 服务器/客户端。我以这样的方式编写程序,即我们在客户端发送的任何内容都逐行显示在服务器中,直到键入退出。该程序可以运行,但数据最后一起显示在服务器中。有人可
我正在使用微 Controller 与 SIM808 模块通信,我想发送和接收 AT 命令。 现在的问题是,对于某些命令,我只收到了我应该收到的答案的一部分,但对于其他一些命令,我收到了我应该
我用c设计了一个消息传递接口(interface),用于在我的系统中运行的不同进程之间提供通信。该接口(interface)为此目的创建 10-12 个线程,并使用 TCP 套接字提供通信。 它工作正
我需要澄清一下在套接字程序中使用多个发送/接收。我的客户端程序如下所示(使用 TCP SOCK_STREAM)。 send(sockfd,"Messgfromlient",15,0);
我正在构建一个真正的基本代理服务器到我现有的HTTP服务器中。将传入连接添加到队列中,并将信号发送到另一个等待线程队列中的一个线程。此线程从队列中获取传入连接并对其进行处理。 问题是代理程序真的很慢。
我正在使用 $routeProvider 设置一条类似 的路线 when('/grab/:param1/:param2', { controller: 'someController',
我在欧洲有通过 HLS 流式传输的商业流媒体服务器。http://europe.server/stream1/index.m3u8现在我在美国的客户由于距离而遇到一些网络问题。 所以我在美国部署了新服
我有一个长期运行的 celery 任务,该任务遍历一系列项目并执行一些操作。 任务应该以某种方式报告当前正在处理的项目,以便最终用户知道任务的进度。 目前,我的django应用程序和celery一起坐
我需要将音频文件从浏览器发送到 python Controller 。我是这样做的: var xmlHttp = new XMLHttpRequest(); xmlHttp.open( "POST",
我是一名优秀的程序员,十分优秀!