C# 在.Net Core中使用X509证书对字节数组进行签名
我想用C# 在.Net Core中使用X509证书对字节数组进行签名,c#,cryptography,.net-core,sign,pkcs#12,C#,Cryptography,.net Core,Sign,Pkcs#12,我想用X509Certificate2为字节数组签名 以下是的示例,但我需要与.Net Core相同的示例: var argCertFirmante = new X509Certificate2(file, pass); var infoContenido = new ContentInfo(argBytesMsg); var cmsFirmado = new SignedCms(infoContenido); var cmsFirmante = new CmsSigner(argCer
X509Certificate2
为字节数组签名
以下是的示例,但我需要与.Net Core相同的示例:
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.cms-in ticket.xml-outform DER-nodetach
- openssl base64-in-ticket.xml.cms-out-ticket.xml.cms.base64
<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" />
根据Apisof.Net的
Apisof.Net
,这两个类都不会被移植到.Net内核。在这里,您可以做两件事:
- 等待.Net Core的2.0版本,以便您能够使用,并使用
对象对数据进行签名非对称gorithm
- 或者您可以使用:
具有用于算法的静态名称,并具有用于填充的默认对象。根据Apisof.Net,这两个类都是类,不会被移植到.Net核心。在这里,您可以做两件事:
- 等待.Net Core的2.0版本,以便您能够使用,并使用
对象对数据进行签名非对称gorithm
- 或者您可以使用:
具有用于算法的静态名称,并具有用于填充的默认对象。SignedCms在.NET Core 1.0或1.1中不可用;2.0版也不会。(编辑:它将在即将发布的2.1版本中提供) 如果您只关心写入数据(这比读取数据容易得多),则可以使用RSA.SignData实现有限形式的数据 SignedCms生成DER编码的CMS签名数据值(),该值为
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)编写数据,即(尽管它构建了许多ASN.1,并引用了ASN.1,即)
假设您想用SHA-2-256/RSA+SHA-2-256来签署“Hello”。当然,我们在密码学中没有字符串,所以这是字节序列48656c6c6f
// 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”系列字节是80 01 00
“l”系列是完整的,它包含13个字节,因此0D
(没有y或z字节)
“k”在11字节处完成(0B
)
“j”取决于序列号的长度。我的证书的序列号为9B 5D E6 C1 51 26 A5 8B,但您不应该将其记为负数(第一个字节设置了高位),因此它需要一个填充字节,使内容00 9B 5D E6 C1 51 26 A5 8B
,因此长度为9(09
)
“i”取决于发行人名称的长度。我的数组是141字节(已经DER编码),加上我们的序列号(9字节+标签+长度==11字节)=>152字节(0x98)。由于0x98大于0x7F,我们必须在其前面加上长度前缀:81 98
现在“h”完成了。(3+(1+2+152)+(1+1+11)+(1+1+13)+(1+3+256)=>446=0x1BE=>82 01 BE
“g”是(1+3+446)=>450=0x1C282 01 C2
“f”是您编码的所有证书的总和。我的结果是683=0x2AB(82 02 AB
)
“e”是7(07
)
“d”是11+(1+1+7)=20=0x14(14
)
“c”是11(0B
)
“b”是(1+1+11)=13(0D
)
“a”是3+(1+1+13)+(1+1+11)+(1+3+683)+(1+3+450)=1172=0x494(820494
)
如果你走这条路,你会得到像
openssl asn1parse-i-dump-inform DER
或其他类似的DER阅读器/渲染工具的帮助。SignedCms在.NET Core 1.0或1.1中不可用;在2.0中也不可用。(Edit:它将在即将发布的2.1版本中可用)
如果您只关心写入数据(这比读取数据容易得多),则可以使用RSA.SignData实现有限形式的数据
SignedCms生成DER编码的CMS签名数据值(),该值为
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)编写数据,即(尽管它构建了许多ASN.1,并引用了ASN.1,即)
假设您想用SHA-2-256/RSA+SHA-2-256来签署“Hello”。当然,我们在密码学中没有字符串,所以这是字节序列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”字节序列是80 01 00
“l”系列是完整的,它包含13个字节,因此0D
(没有y或z字节)
“k”在11字节处完成(0B
)
“j”取决于序列号的长度。我的证书具有序列号9B 5D E6 C1 51 26 A5 8B
,但您不应该将其记为负数(第一个字节设置了高位),因此它需要一个填充字节,使内容00 9B 5D E6 C1 51 26 A5 8B
,因此长度为9(09
)
“i”取决于发卡机构名称的长度。我的名称是141字节数组(已经DER编码),加上我们的序列号(9字节+标记+长度==11字节)=>152字节(0x98)。因为0x98大于0x7F,所以我们必须在长度前加前缀:81 98
现在“h”完成了。(3+(1+2)+