SignedCms在.NET Core 1.0或1.1中不可用;也不會在2.0。 (編輯:它將在即將發佈的2.1版本中提供)。
如果你只關心寫入數據(這比讀取數據容易得多),那麼你可以使用RSA.SignData來實現它的有限形式。
SignedCms產生編碼的CMS一個DER簽署數據值(RFC 5652, section 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簽名「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 + 152)+(1 + 1 + 11)+(1 + 1 + 13)+(1 + 3 + 256)=> 446 = 0x1BE =>82 01 BE
。
「g」爲(1 + 3 + 446)=> 450 = 0x1C2 82 01 C2
。
「f」 爲你編碼的所有證書的總和。礦出來683 = 0x2AB(82 02 AB
)
「E」 是7(07
)
「d」 是11 +(1 + 1 + 7)= 20 = 0×14(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(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 Editor,或其他如DER讀/渲染工具輔助。
您是否希望使用.net-core進行跨平臺或僅適用於Windows? –
是.net-core中的跨平臺 –