在 .NET 中加载椭圆曲线 (EC) 密钥
在 .NET 中加載橢圓曲線 (EC) 密鑰
本文將討論在.NET 中解析和加載EC 密鑰的不同方式。在本文中,您將了解 EC 密鑰的構成,然后了解如何以四種不同的方式使用這些知識ECDsa在 .NET 中加載或創建對象。到本文結束時,您應該能夠加載 EC 密鑰,無論格式如何。
本文針對 .NET Core 3.1 及更高版本。
橢圓曲線 (EC) 密鑰的參數
加載 EC 密鑰時,您將需要了解三件事:
1.私鑰(可選)2.公鑰3.您需要使用的曲線
私鑰d是一個隨機整數,其長度取決于您使用的曲線。如果你有私鑰,你就可以對數據進行簽名。
公鑰是橢圓曲線上的一個點,使用坐標x&y。因此,公鑰特定于該曲線,并使用私鑰乘以曲線上的生成點G生成。使用公鑰,您將能夠驗證簽名。
這表明您需要了解正在使用的橢圓曲線(例如,NIST 的 P-256[1]或secp256k1[2])才能使用橢圓曲線加密 (ECC)。如果不知道曲線,您將不知道私鑰應該有多長、提供的安全級別或公鑰是否有效(如果它們是曲線上的點)。
如果您想了解有關橢圓曲線密碼學工作原理的更多信息,我發現開發人員實用密碼學[3]是一本有用的讀物。
.NET 的ECDsa對象
.NET 對 ECDSA 的抽象是ECDsa在System.Security.Cryptography. 這繼承AsymmetricAlgorithm并遵循RSA您之前可能使用過的類的類似模式。?ECDsa是一個抽象類,具有使用不同實現的各種平臺(例如,Windows 上的 CNG 和 Linux 上的 OpenSSL)。
此類的主要用途是調用SignData和VerifyData方法。否則,您可能會將其傳遞到SecurityKey 實現[4]或 SignedXml。
本文的其余部分將重點介紹如何創建ECDsa實現。
使用ECDsa和命名曲線生成 EC 密鑰
創建新 EC 密鑰的最簡單方法是使用 .NETCreate上的方法讓 .NET 為您完成ECDsa。這將在您選擇的曲線上創建一個私鑰。您通常會使用已知的命名曲線,例如 NIST 的 P-256,又名 secp256r1。您可以在ECCurve.NamedCurve課程中找到 .NET 支持的開箱即用曲線。
ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP256);這種方法非常適合在測試期間即時生成密鑰,但是一旦對象被處置,您就會丟失密鑰。幸運的是,您可以使用各種導出方法ECDsa;否則,您可以使用該ExportParameters方法直接訪問 EC 參數。這些導出方法使您可以訪問ECParameters包含關鍵點曲線、D 和 Q ( x & y ) 點的對象,您將在接下來的操作中看到這些點。
創建ECDSA使用為ECParameters
假設您已經收到曲線的原始點,并且您需要以這種方式加載密鑰。這在使用 JSON Web Keys (JWK) 和OpenID Connect[5]時很常見。
這是來自 RFC 7517 的 JWK 示例:
{"kty": "EC","crv": "P-256","x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU","y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0","kid": "my EC key" }要加載密鑰,您需要知道密鑰使用什么曲線以及公鑰參數(x和y坐標)。也可以使用d參數將私鑰包含在 JWK 中;然而,這種情況很少見。
您可以再次使用ECDsa的Create方法加載這些坐標,但這次您將傳入一些ECParameters.
// parse curve from JOSE format // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve var curve = crv switch {"P-256" => ECCurve.NamedCurves.nistP256,"P-384" => ECCurve.NamedCurves.nistP384,"P-521" => ECCurve.NamedCurves.nistP521,_ => throw new NotSupportedException() };ECDsa key = ECDsa.Create(new ECParameters {Curve = curve,D = Base64UrlEncoder.DecodeBytes(d), // optionalQ = new ECPoint{X = Base64UrlEncoder.DecodeBytes(x),Y = Base64UrlEncoder.DecodeBytes(y)} });在這里,您正在解析 JOSE 名稱中的曲線,并使用 中找到的編碼器對其他參數進行 base64url 解碼Microsoft.IdentityModel.Tokens。
此解析特定于 JWK 使用的格式,但它演示了如何在知道其參數的情況下加載 EC 密鑰。
有一種Validate方法ECParameters可以檢查關鍵和坐標大小并檢查曲線是否有效。但是,Createon的方法ECDsa會為您調用它。
如果您確實有 JWK 并打算使用它來驗證 JWT,我建議將 JWK 直接傳遞到構造函數中Microsoft.IdentityModel.Tokens.JsonWebKey并跳過我在上面演示的手動解析。
從X509Certificate2加載ECDsa
從 an 加載 EC 密鑰X509Certificate2是簡單使用GetECDsaPrivateKey和GetECDsaPublicKey方法的一種情況。
ECDsa key = cert.HasPrivateKey ? cert.GetECDsaPrivateKey() : cert.GetECDsaPublicKey();為了首先加載X509Certificate2,您可以從 PEM 文件加載它[6]。
X509Certificate2.PrivateKey與GetRSAPrivateKey和GetECDsaPrivateKey
過去,您可能在 上使用了PrivateKey和PublicKey屬性X509Certificate2。但是,如果您嘗試在包含 EC 密鑰的證書上使用這些屬性,您將獲得 null forPrivateKey和以下異常PublicKey:
System.NotSupportedException: 不支持證書密鑰算法。在 System.Security.Cryptography.X509Certificates.PublicKey.get_Key()要使用來自 X.509 的 EC 密鑰,您需要使用GetECDsaPrivateKey和GetECDsaPublicKey方法。
從 .NET 6 開始,PrivateKey和PublicKey屬性被標記為過時。因此,您必須使用RSA和ECDsa特定方法來全面加載密鑰。
從十六進制字符串加載ECDsa
有時,您會看到 EC 密鑰作為十六進制字符串共享。這在加密社區中很常見,我的意思是密碼學和加密貨幣。我不能說它在密碼學中是否有很大用處。這些鍵看起來像這樣:
Private: c711e5080f2b58260fe19741a7913e8301c1128ec8e80b8009406e5047e6e1ef Public: 04e33993f0210a4973a94c26667007d1b56fe886e8b3c2afdd66aa9e4937478ad20acfbdc666e3cec3510ce85d40365fc2045e5adb7e675198cf57c6638efa1bdb這些鍵起初可能看起來有點奇怪,但它們實際上映射回您已經使用的參數。私鑰只是d參數的十六進制表示,公鑰是連接在一起的x &y坐標(第一個字節是標簽)。
因此,您可以再次使用ECParameters來創建您的ECDsa對象:
public static ECDsa LoadFromHex() {var privateKeyBytes = FromHexString("c711e5080f2b58260fe19741a7913e8301c1128ec8e80b8009406e5047e6e1ef");var publicKeyBytes = FromHexString("04e33993f0210a4973a94c26667007d1b56fe886e8b3c2afdd66aa9e4937478ad20acfbdc666e3cec3510ce85d40365fc2045e5adb7e675198cf57c6638efa1bdb");return ECDsa.Create(new ECParameters{Curve = ECCurve.NamedCurves.nistP256, // you'd need to know the curve before handD = privateKeyBytes,Q = new ECPoint{X = publicKeyBytes.Skip(1).Take(32).ToArray(),Y = publicKeyBytes.Skip(33).ToArray()}}); }private static byte[] FromHexString(string hex) {var numberChars = hex.Length;var hexAsBytes = new byte[numberChars / 2];for (var i = 0; i < numberChars; i += 2)hexAsBytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);return hexAsBytes; }源代碼
您可以在我的GitHub 示例存儲庫中[7]找到演示上述方法的可執行代碼。此代碼是多目標 .NET Core 3.1 及以上版本,可在 Windows 和 Linux 上運行。
查看原文:https://www.scottbrady91.com/c-sharp/ecdsa-key-loading
References
[1]?NIST 的 P-256:?https://www.scottbrady91.com/C-Sharp/JWT-Signing-using-ECDSA-in-dotnet-Core
[2]?secp256k1:?https://www.scottbrady91.com/C-Sharp/Supporting-Custom-JWT-Signing-Algorithms-in-dotnet-Core
[3]?開發人員實用密碼學:?https://cryptobook.nakov.com/asymmetric-key-ciphers/elliptic-curve-cryptography-ecc
[4]?SecurityKey 實現:?https://www.scottbrady91.com/C-Sharp/JWT-Signing-using-ECDSA-in-dotnet-Core
[5]?OpenID Connect:?https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Overview
[6]?從 PEM 文件加載它:?https://www.scottbrady91.com/C-Sharp/PEM-Loading-in-dotnet-core-and-dotnet
[7]?GitHub 示例存儲庫中:?https://github.com/scottbrady91/Blog-Example-Classes/tree/master/EcdsaKeyLoading
總結
以上是生活随笔為你收集整理的在 .NET 中加载椭圆曲线 (EC) 密钥的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#10在List, Queue 以及S
- 下一篇: ASP.NET Core官方文档+源码,