我想用 X509Certificate2
,
这是.NET Framework 4.7的示例,但是我需要.NET核心:
var argCertFirmante = new X509Certificate2(file, pass);
var infoContenido = new ContentInfo(argBytesMsg);
var cmsFirmado = new SignedCms(infoContenido);
var cmsFirmante = new CmsSigner(argCertFirmante)
{ IncludeOption = X509IncludeOption.EndCertOnly };
cmsFirmado.ComputeSignature(cmsFirmante, true);
return cmsFirmado.Encode();
我想要等同于此:
- openssl smime -sign -signer ebookingv4.crt -inkey ebookingv4.key -out ticket.xml.xml.cms -in ticket.xml -outform der -nodetach
- openssl base64 -in ticket.xml.cms -out ticket.xml.cms.base64
加密消息语法(CMS(使用Net Core 2.0和此Nuget软件包,我对我来说很好:
<PackageReference Include="System.Security.Cryptography.Algorithms"
Version="4.4.0-beta-24913-01" /> <PackageReference
Include="System.Security.Cryptography.Pkcs"
Version="4.5.0-preview1-26119-06" /> <PackageReference
Include="System.Security.Cryptography.X509Certificates"
Version="4.4.0-beta-24913-01" />
在.NET CORE 1.0或1.1中不可用签名。它也不会在2.0中。( edit :它将在即将发布的2.1版本中使用(。
如果您只关心编写数据(这比阅读要容易得多(,则可以使用RSA.Signdata实现有限的形式。
SignedCMS产生一个编码的CMS签名数据值(RFC 5652,第5节(,这是
SignedData ::= SEQUENCE {
version CMSVersion,
digestAlgorithms DigestAlgorithmIdentifiers,
encapContentInfo EncapsulatedContentInfo,
certificates [0] IMPLICIT CertificateSet OPTIONAL,
crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
signerInfos SignerInfos
}
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
SignerInfos ::= SET OF SignerInfo
为了编写一个,您需要了解如何根据杰出的编码规则(DER((即ITU-T X.690(编写数据(尽管它在ASN.1上构建很多,并进行引用至ASN.1,即ITU-T X.680(。
想象您想签名"您好"使用SHA-2-256/RSA SHA-2-256。当然,我们没有密码学中的字符串,所以这是字节序列48 65 6C 6C 6F
。
// SEQUENCE (SignedData)
30 xa [ya [za]]
// INTEGER (Version=1)
02 01 01
// SET (OF DigestAlgorithmIdentifier (digestAlgorithms))
31 xb [yb [zb]]
// SEQUENCE (DigestAlgorithmIdentifier ::= AlgorithmIdentifier)
30 xc [yc [zc]]
// OBJECT IDENTIFIER (2.16.840.1.101.3.4.2.1 == SHA-2-256)
06 09 60 86 48 01 65 03 04 02 01
// SEQUENCE (EncapsulatedContentInfo)
30 xd [yd [zd]]
// OBJECT IDENTIFIER (1.2.840.113549.1.7.1 == pkcs7-data)
06 09 2A 86 48 86 F7 0D 01 07 01
// CONTEXT SPECIFIC 0 - CONSTRUCTED
A0 xe [ye [ze]]
// OCTET STRING (the data goes here)
04 05 48 65 6C 6C 6F // "Hello"
// CONTEXT SPECIFIC 0 - CONSTRUCTED (CertificateSet (certificates))
A0 xf [yf [zf]]
[cert.RawData goes here, which is already DER encoded]
[do you have an intermediate you want to share?
okay, write intermediate.RawData here; repeat]
// skip the crls.
// SET (OF SignerInfo (singerInfos))
31 xg [yg [zg]]
// SEQUENCE (SignerInfo)
30 xh [yh [zh]]
// INTEGER (Version=1)
02 01 01
// SEQUENCE (IssuerAndSerialNumber)
30 xi [yi [zi]]
// SEQUENCE (Issuer)
[cert.IssuerName.RawData]
// OCTECT STRING (SerialNumber)
02 xj [yj [zj]]
[cert.GetSerialNumberBytes() (see note "j")]
// SEQUENCE (DigestAlgorithm (digestAlgorithm))
30 xk [yk [zk]]
// OBJECT IDENTIFIER (2.16.840.1.101.3.4.2.1 == SHA-2-256)
06 09 60 86 48 01 65 03 04 02 01
// skip signedAttrs
// SEQUENCE (DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier)
30 xl [yl [zl]]
// OBJECT IDENTIFIER (1.2.840.113549.1.1.1 == rsaEncryption)
06 09 2A 86 48 86 F7 0D 01 01 01
// NULL (rsaEncryption says parameters must be explicit NULL)
05 00
// OCTECT STRING (signature)
04 xm [ym [zm]]
[rsa.SignData(
new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F },
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1)]
// skip unsignedAttrs
现在我们完成了,我们可以关闭所有缺失的长度。签名大小是RSA键的函数。假设它是一个2048位键,它是2048位签名,即256个字节。256是0x100,大于0x7f,因此我们必须将其分解为两个长度字节和一个长度长度:因此" m&quot"系列字节是80 01 00
。
" l&quot"系列完成,包含13个字节,因此0D
(没有Y或Z字节(。
" k&quot"完成为11个字节(0B
(。
" J&quot"取决于序列号的时间。我的证书具有序列号9B 5D E6 C1 51 26 A5 8B
,但是您不应该将其写入负数(首先字节具有高钻头(,因此它需要一个填充字节,使内容00 9B 5D E6 C1 51 26 A5 8B
,因此长度为9(09
((。
" i i&quot"取决于发行人名称的长度。我的序列阵列(已经编码了(,加上我们的序列号(9个字节 tag 长度== 11个字节(=&gt;152字节(0x98(。由于0x98大于0x7f,因此我们必须长度回顾: 81 98
。
现在" h"已经完成了。(3 (1 2 152( (1 1 11( (1 1 13( (1 3 256(=&gt; 446 = 0x1be =&gt; 82 01 BE
。
" g&quot"IS(1 3 446(=&gt;450 = 0x1C2 82 01 C2
。
" f&quot"是您编码的所有证书的总和。我的出现到683 = 0x2ab(82 02 AB
(
'e&quot是7(07
(
'd&quot是11 (1 1 7(= 20 = 0x14(14
(
" c&quot"是11(0B
(
" b&quot"IS(1 1 11(= 13(0D
(
" a"是3 (1 1 13( (1 1 11( (1 3 683( (1 3 450(= 1172 = 0x494(82 04 94
(。
30 82 04 94 02 01 01 31 0D 30 0B 06 09 60 86 48
01 65 03 04 02 01 30 14 06 09 2A 86 48 86 F7 0D
01 07 01 A0 07 04 05 65 6C 6C 6F A0 82 02 AB ...
...cert.RawData...
31 82 01 C2 30 82 01 BE 02 01 01 30 81 98 ...
...cert.IssuerName.RawData...
02 09 00 9B 5D E6 C1 51 26 A5 8B 30 0B 06 09 60
86 48 01 65 03 04 02 01 30 0D 06 09 2A 86 48 86
F7 0D 01 01 01 05 00 04 80 01 00 ... signature ...
如果您走这条路线,您将获得openssl asn1parse -i -dump -inform DER < your.signed.cms
或ASN.1编辑器或其他此类der读取器/渲染工具等工具的协助。
根据Apisof.Net
,SignedCms
和CmsSigner
的两个类都不会移植到.NET Core。您可以做的是两件事:
- 等待2.0版的.NET Core,因此您可以使用
PrivateKey
属性,并使用AsymmetricAlgorithm
对象签署数据 -
,或者您可以使用
extension
方法GetRSAPrivateKey(X509Certificate2)
:public byte[] Sign(string message) { using (var key = certificate.GetRSAPrivateKey()) { return key.SignData(Encoding.UTF8.GetBytes(message), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } }
HashAlgorithmName
具有用于算法的静态名称,RSASignaturePadding
具有用于填充的默认对象。