2017-04-23 51 views
1

我要籤個字節與X509Certificate2陣列,註冊與X509證書的字節數組中的.Net核心

下面是.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退房手續ticket.xml.cms -in ticket.xml -outform DER -nodetach
  • 的OpenSSL的base64 -in ticket.xml.cms退房手續ticket.xml.cms.base64

Cryptographic Message Syntax (CMS) 配網核心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" /> 
+0

您是否希望使用.net-core進行跨平臺或僅適用於Windows? –

+0

是.net-core中的跨平臺 –

回答

2

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.cmsASN.1 Editor,或其他如DER讀/渲染工具輔助。

3

根據Apisof.Net,類別SignedCmsCmsSigner將不會移植到.Net Core。你可以做的是在這裏兩件事情:

  • 等待一個2.0版本的.NET核心的,所以你可以使用PrivateKey property,並使用AsymmetricAlgorithm對象對數據進行簽名
  • 或者你可以使用extension methodGetRSAPrivateKey(X509Certificate2)

    public byte[] Sign(string message) 
    { 
        using (var key = certificate.GetRSAPrivateKey()) 
        { 
         return key.SignData(Encoding.UTF8.GetBytes(message), 
          HashAlgorithmName.SHA256, 
          RSASignaturePadding.Pkcs1); 
        } 
    } 
    

HashAlgorithmName有靜態名字的算法和RSASignaturePadding具有默認的對象進行填充。