C#SignedCms的Java实现 [英] Java implementation of C# SignedCms

查看:180
本文介绍了C#SignedCms的Java实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Java实现C#SignedCms功能。

I am working on an implementation of C# SignedCms functionality in Java.

我正在使用bouncycastle libs。
问题是我得到的java签名与SignedCms生成的签名不同。

I am using bouncycastle libs. The problem is I get java signature that is different from the one generated with SignedCms.

X509Certificate2 certificate = new X509Certificate2("myCertPath", "myPass"); 
String text = "text"; 
ContentInfo contentInfo = new ContentInfo(System.Text.Encoding.UTF8.GetBytes(text)); 
SignedCms cms = new SignedCms(contentInfo, false); 
CmsSigner signer = new CmsSigner(certificate); 
signer.IncludeOption = X509IncludeOption.None; 
signer.DigestAlgorithm = new Oid("SHA1"); 
cms.ComputeSignature(signer, false); 
byte[] signature = cms.Encode(); 
print(signature); 






Java代码




Java code

Security.addProvider(new BouncyCastleProvider()); 
char[] password = "myPass".toCharArray(); 
String text = "text"; 
FileInputStream fis = new FileInputStream("myCertPath"); 
KeyStore ks = KeyStore.getInstance("pkcs12"); 
ks.load(fis, password); 

String alias = ks.aliases().nextElement(); 
PrivateKey pKey = (PrivateKey)ks.getKey(alias, password); 
X509Certificate cert = (X509Certificate)ks.getCertificate(alias); 
java.util.List certList = new ArrayList(); 
Store certs = new JcaCertStore(certList); 

CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); 
JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").setDirectSignature(true); 

gen.addSignerInfoGenerator(builder.build("SHA1withRSA", pKey, cert)); 
gen.addCertificates(certs); 

CMSTypedData msg = new CMSProcessableByteArray(text.getBytes()); 
CMSSignedData s = gen.generate(msg, false); 
print(s.getEncoded()); 

它们都不包含x509证书。

They both don't include x509 certificates.

length = 434
308201AE06092A864886F70D010702A082019F3082019B020101310B300906052B0E03021A0500301306092
A864886F70D010701A006040474657874318201723082016E0201013081CB3081B6310B3009060355040613
02555331173015060355040A130E566572695369676E2C20496E632E311F301D060355040B1316566572695
369676E205472757374204E6574776F726B313B3039060355040B13325465726D73206F6620757365206174
2068747470733A2F2F7777772E766572697369676E2E636F6D2F7270612028632930393130302E060355040
31327566572695369676E20436C617373203320436F6465205369676E696E6720323030392D322043410210
1763F9A88334A01FFB3B7BAB384A9B93300906052B0E03021A0500300D06092A864886F70D0101010500048
1800B866A9A7045E3C86E5DB69CDAD5CED211A4A2362BCC4DDB2742BF0CDB65BC88556C97A6C08D68F8070D
89CC78ACD84A636F15B40D166E461411C6A04D5EC379283988DA4258B684FFEF9F08B293A03A0B40900E245
874D8C0587BBD58BDD915A50D27456E6EEB883846CAC485853BA5E22E45D333C940A 958E641A00C9602B9

length=434 308201AE06092A864886F70D010702A082019F3082019B020101310B300906052B0E03021A0500301306092 A864886F70D010701A006040474657874318201723082016E0201013081CB3081B6310B3009060355040613 02555331173015060355040A130E566572695369676E2C20496E632E311F301D060355040B1316566572695 369676E205472757374204E6574776F726B313B3039060355040B13325465726D73206F6620757365206174 2068747470733A2F2F7777772E766572697369676E2E636F6D2F7270612028632930393130302E060355040 31327566572695369676E20436C617373203320436F6465205369676E696E6720323030392D322043410210 1763F9A88334A01FFB3B7BAB384A9B93300906052B0E03021A0500300D06092A864886F70D0101010500048 1800B866A9A7045E3C86E5DB69CDAD5CED211A4A2362BCC4DDB2742BF0CDB65BC88556C97A6C08D68F8070D 89CC78ACD84A636F15B40D166E461411C6A04D5EC379283988DA4258B684FFEF9F08B293A03A0B40900E245 874D8C0587BBD58BDD915A50D27456E6EEB883846CAC485853BA5E22E45D333C940A958E641A00C9602B9

length = 428
308006092A864886F70D010702A0803080020101310B300906052B0E03021A0500308006092A864886F70D0
107010000318201723082016E0201013081CB3081B6310B300906035504061302555331173015060355040A
130E566572695369676E2C20496E632E311F301D060355040B1316566572695369676E205472757374204E6
574776F726B313B3039060355040B13325465726D73206F66207573652061742068747470733A2F2F777777
2E766572697369676E2E636F6D2F7270612028632930393130302E06035504031327566572695369676E204
36C617373203320436F6465205369676E696E6720323030392D3220434102101763F9A88334A01FFB3B7BAB
384A9B93300906052B0E03021A0500300D06092A864886F70D01010105000481800B866A9A7045E3C86E5DB
69CDAD5CED211A4A2362BCC4DDB2742BF0CDB65BC88556C97A6C08D68F8070D89CC78ACD84A636F15B40D16
6E461411C6A04D5EC379283988DA4258B684FFEF9F08B293A03A0B40900E245874D8C0587BBD58BDD915A50
D27456E6EEB883846CAC485853BA5E22E45D333C940A958 E641A00C9602B9000000000000

length=428 308006092A864886F70D010702A0803080020101310B300906052B0E03021A0500308006092A864886F70D0 107010000318201723082016E0201013081CB3081B6310B300906035504061302555331173015060355040A 130E566572695369676E2C20496E632E311F301D060355040B1316566572695369676E205472757374204E6 574776F726B313B3039060355040B13325465726D73206F66207573652061742068747470733A2F2F777777 2E766572697369676E2E636F6D2F7270612028632930393130302E06035504031327566572695369676E204 36C617373203320436F6465205369676E696E6720323030392D3220434102101763F9A88334A01FFB3B7BAB 384A9B93300906052B0E03021A0500300D06092A864886F70D01010105000481800B866A9A7045E3C86E5DB 69CDAD5CED211A4A2362BCC4DDB2742BF0CDB65BC88556C97A6C08D68F8070D89CC78ACD84A636F15B40D16 6E461411C6A04D5EC379283988DA4258B684FFEF9F08B293A03A0B40900E245874D8C0587BBD58BDD915A50 D27456E6EEB883846CAC485853BA5E22E45D333C940A958E641A00C9602B9000000000000

我遇到了这个问题。
说实话,我很绝望,不知道出了什么问题。

I get stuck on this issue. To be honest, I'm desperate, and have no idea what's wrong.

感谢任何帮助。

UPD。

Java输出是BER编码的。我需要DER编码签名。
将BER转换为DER我使用

The Java output was BER encoded. I needed DER encoded signature. To convert BER to DER I used

ByteArrayOutputStream bOut = new ByteArrayOutputStream();
DEROutputStream dOut = new DEROutputStream(bOut);
dOut.writeObject(s.toASN1Structure().toASN1Primitive());
dOut.close();
bytep[ encoded = bOut.toByteArray();

现在输出是相同的。

非常感谢。

推荐答案

好消息:没有错。

查看两个结果DER编码的开头:

Take a look at the beginning of both resulting DER encodings:

C#:   308201AE...
Java: 3080...

C#编码具有明确的长度形式,即 30 表示 SEQUENCE 82 表示使用接下来的两个字节的明确长度编码, 01AE 是430的实际长度值。接下来的430个字节加上到目前为止的4个读取总计434个字节。

The C# encoding is in definite length form, i.e. 30 indicates a SEQUENCE, 82 indicates a definite length encoding using the next two bytes, and 01AE is the actual length value of 430. 430 bytes that follow plus the 4 read so far make up for the total of 434 bytes.

另一方面,Java编码不同因为它表示无限长度编码( 80 )。严格地说,这不再是DER编码而是BER编码。这意味着没有给出该元素的显式长度,但该元素以一个特殊的 END OF CONTENTS 元素结束,而是编码为 0000 。在Java编码结束时你会注意到它们中的很多。有关BER / DER的本指南中的详细信息。

The Java encoding on the other hand differs in that it indicates an indefinite length encoding (the 80). Strictly speaking, this is no longer a DER encoding but a BER encoding. This means that no explicit length is given for that element, but that the element ends with a special END OF CONTENTS element instead, which is encoded as 0000. You'll notice quite a few of them at the end of the Java encoding. More about the details in this guide to BER/DER.

这两个结构的其余部分完全相同,甚至是签名值本身。只是Java版本使用不定长度,而C#版本使用明确的长度。如果验证方同时理解BER和DER编码,则两个签名在编码时将是相同的。编码不会在签名验证过程中发挥作用。以下是 CMS RFC 对此的说法:

The rest of the two structures is exactly identical, even the signature value itself. It's just that the Java version uses indefinite lengths while the C# version uses definite lengths. If the verifying party understands both BER and DER encodings, the two signatures will be identical up to encoding. And the encoding won't play a role in the signature verification process. Here's what the CMS RFC says with regard to this:

使用 signedAttrs 现在:


具体来说,初始输入是应用签名过程

encapContentInfo电子内容OCTET STRING。只有包含eContent
OCTET STRING值的八位字节输入到消息摘要算法,而不是标记
或长度八位字节。

Specifically, the initial input is the encapContentInfo eContent OCTET STRING to which the signing process is applied. Only the octets comprising the value of the eContent OCTET STRING are input to the message digest algorithm, not the tag or the length octets.

没有 signedAttrs


当signedAttrs字段时如果不存在,则只有包含SignedData encapContentInfo eContent OCTET STRING的
值的八位字节(例如,
文件的内容)被输入到消息摘要计算中。
这样做的好处是签名生成过程之前无需知道签名内容
的长度。

When the signedAttrs field is absent, only the octets comprising the value of the SignedData encapContentInfo eContent OCTET STRING (e.g., the contents of a file) are input to the message digest calculation. This has the advantage that the length of the content being signed need not be known in advance of the signature generation process.

换句话说:只有包含 eContent 实际值的字节被散列,实际上只有那些。它的标签及其长度以及它的块的标签和长度(在不确定的构造编码的情况下)都不会在该过程中被散列。我承认,有些实现会出错,这显然是一个非常复杂的问题。

In other words: Only the bytes comprising the actual value of the eContent are hashed, and really only those. Neither its tag nor its length and also not the tags and lengths of its chunks (in the case of an indefinite constructed encoding) may be hashed in the process. I'll admit, there are implementations that get this wrong and it's clearly a quite complicated issue.

虽然它增加了很多复杂性和互操作性问题,但由于一个原因(除了减少几个字节)之外它是有意义的:如果你生成'附加签名'(原始文档嵌入的那些)在 EncapContentInfo 元素中,选择不定长度允许您以流方式创建和验证签名:您可以按块读取或写入块。然而,对于确定的长度,您必须立即读取/写入整个事物,因为您需要提前知道长度,以便创建DER编码的最终Tag-Length-Value格式。在这种情况下,能够进行流式IO的想法是非常强大的:想象一下你想创建几GB大的日志文件的附加签名 - 任何非流式方法都会很快耗尽内存。

While it adds a lot of complexity and interoperability issues, it makes sense for one reason (besides being a few bytes smaller): If you produce 'attached signatures' (the ones where the original document is embedded within the EncapContentInfo element), choosing indefinite lengths allows you to create and verify the signature in a streaming manner: you can read or write chunk by chunk. Whereas for definite lengths you have to read/write the whole thing at once because you need to know the length in advance in order to create the final Tag-Length-Value format of DER encoding. The idea of being able to do streaming IO is very powerful in this context: imagine you want to create an attached signature of a log file several GB large - any non-streaming approach will quickly run out of memory.

Java版的Bouncy Castle不久前在CMS的上下文中添加了流媒体支持,很可能很高,不会太长,直到C#版本才能获得它。

The Java version of Bouncy Castle added streaming support in the context of CMS a while ago, chances are high that it won't be too long until the C# version picks it up.

这篇关于C#SignedCms的Java实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆