2017-05-15 110 views
0

我正在嘗試創建一個C#實現,以便通過Docker中的.Net核心通過其HTTP/2 APNS端點將Apple推送到Apple。其中一部分要求將加密的JWT授權令牌與有效負載一起發送。使用.Net核心,我可以在Windows上運行時簽署令牌,但在Linux Docker映像中運行時,它會提示加載密鑰。ECDsa在Linux上登錄.Net核心

在.net核心Docker鏡像中運行時,加載密鑰時出現platformnotsupport Exception異常。

public static string SignES256(string privateKey, string header, string payload) 
    { 

     // This is the failing Call 
     CngKey key = CngKey.Import(Convert.FromBase64String(privateKey), CngKeyBlobFormat.Pkcs8PrivateBlob); 

     using (ECDsaCng dsa = new ECDsaCng(key)) 
     { 
      var unsignedJwtData = 
       System.Convert.ToBase64String(Encoding.UTF8.GetBytes(header)) + "." + System.Convert.ToBase64String(Encoding.UTF8.GetBytes(payload)); 
      var unsignedJwtDataBytes = Encoding.UTF8.GetBytes(unsignedJwtData); 

      var signature = 
       dsa.SignData(unsignedJwtDataBytes, 0, unsignedJwtDataBytes.Length, HashAlgorithmName.SHA256); 
      return unsignedJwtData + "." + System.Convert.ToBase64String(signature); 
     } 
    } 

如何從Linux上的.Net Core執行此操作?

謝謝。

回答

1

ECDsaCng是使用Windows CNG的ECDSA實現。它特定於Windows,因此在Linux上不受支持。

跨平臺的方式做到這將是

using (ECDsa ecdsa = ECDsa.Create()) 
{ 
    ecdsa.ImportParameters(Pkcs8ToParameters(privateKey)); 

    // the stuff in your current using 
} 

當然,PKCS#8爲ECParameters是不是世界上最容易的事情。但我們可以放棄它。在another answer中,有一個爲RSA構建PKCS#8的細節。

讓我們這個斑點:

308187020100301306072A8648CE3D020106082A8648CE3D030107046D306B02 
0101042070A12C2DB16845ED56FF68CFC21A472B3F04D7D6851BF6349F2D7D5B 
3452B38AA144034200048101ECE47464A6EAD70CF69A6E2BD3D88691A3262D22 
CBA4F7635EAFF26680A8D8A12BA61D599235F67D9CB4D58F1783D3CA43E78F0A 
5ABAA624079936C0C3A9 

它打破了像

30 /* SEQUENCE */ 
    81 87 (payload is 0x87 bytes) 

    02 /* INTEGER */ 01 (1 byte) 00 // Integer: 0. // validate this 

    30 /* SEQUENCE */ 13 (0x13 bytes) 

     06 /* OBJECT IDENTIFIER */ 07 (7 bytes) 
     2A8648CE3D0201 (1.2.840.10045.2.1/ecPublicKey) // validate this 

     06 /* OBJECT IDENTIFIER */ 08 (8 bytes) 
     2A8648CE3D030107 (1.2.840.10045.3.1.7/secp256r1) // save this, curveName 

    04 /* OCTET STREAM (byte[]) */ 6D (0x6D bytes) 
     // Since the constructed (0x20) bit isn't set in the tag normally we stop here, 
     // but we know from the ecPublicKey context that this is also DER data. 

     30 /* SEQUENCE */ 6B (0x6B bytes) 

     02 /* Integer */ 01 (1 byte) 01 // Integer: 1. // validate this. 

     04 /* OCTET STREAM (byte[]) */ 20 (0x20 bytes/256 bits) 
      70A12C2DB16845ED56FF68CFC21A472B3F04D7D6851BF6349F2D7D5B3452B38A // save this: D 

     A1 /* CONSTRUCTED CONTEXT SPECIFIC 1 */ 44 (0x44 bytes) 

      03 /* BIT STRING (byte[] if the first byte is 0x00) */ 66 (0x66 bytes) 

       00 // Oh, good, it's a normal byte[]. Validate this. 

       // Formatting will become apparent. Save this. 
       04 
       8101ECE47464A6EAD70CF69A6E2BD3D88691A3262D22CBA4F7635EAFF26680A8 
       D8A12BA61D599235F67D9CB4D58F1783D3CA43E78F0A5ABAA624079936C0C3A9 

末比特串 「公鑰」。由於它始於04(通常情況下,除非發件人對你生氣),它代表一個「未壓縮點」,這意味着左邊的前半部分是X座標,其餘部分是Y座標。所以從這個結構中你可能會得到這樣的

string curveOid; 

// You can decode the OID, or special case it. 
switch (curveName) 
{ 
    case "2A8648CE3D030107": 
     // secp256r1 
     curveOid = "1.2.840.10045.3.1.7"; 
     break; 
    case "2B81040022" 
     // secp384r1 
     curveOid = "1.3.132.0.34"; 
     break; 
    case "2B81040023": 
     // secp521r1 
     curveOid = "1.3.132.0.35"; 
     break; 
    default: 
     throw new InvalidOperationException(); 
} 

return new ECParameters 
{ 
    Curve = ECCurve.CreateFromValid(curveOid), 

    // We saved this. 
    D = d, 

    Q = new ECPoint 
    { 
     X = x, 
     Y = y 
    }, 
} 

這發生在D1部分的Suite B Implementer’s Guide to FIPS 186-3 (ECDSA)(NIST P-256/secp256r1)所使用的密鑰。

由於EC密鑰格式在INTEGER值(可能需要填充字節)上很短,您可以爲您想要支持的每個密鑰大小構建一個手動提取器。或者你可以去現場DER閱讀路線。或者您可以嘗試讓您的私鑰以更友好的形式序列化,以供您的應用程序使用。