Dot-Net

將基於 ECC 的證書從 Windows 證書儲存導入 CngKey

  • March 24, 2021

如何從基於 ECC 的X509Certificate2‘s中獲取公鑰/私鑰CngKey以與ECDsaCngand一起使用ECDiffieHellmanCng

我目前正在使用 RSA 2048 位密鑰對來簽署/加密內容。我這樣做是通過從X509Store安全儲存證書的位置提取證書,並使用標記為不可導出的私鑰。我想將目前的實現轉換為使用 ECDSA 和 ECDH,以便我可以使用較小的密鑰大小來實現同等的安全性。

我已經使用 openssl 成功生成了 ECC 證書:

  1. openssl ecparam -out private.pem -name prime256v1 -genkey
  2. openssl req -new -key private.pem -x509 -nodes -days 365 -out public.cer
  3. openssl pkcs12 -export -in public.cer -inkey private.pem -out export.pfx

我已成功將上述生成的證書安裝到證書儲存中。我可以通過指紋檢索它們,但私鑰和公鑰的加密提供程序會拋出“不支持算法”異常。相反,我知道我應該使用ECDsaCngECDiffieHellmanCng簽名/加密。但這些處理在CngKey‘s。

Bouncy Castle 不是一個選項,因為它要求私鑰是可導出的。

CLR Security將通過返回給我一CngKey對,GetCngPrivateKey但它不能與 EC​​Dsa 一起使用,因為 CLRSecurity 返回的密鑰是 ECDH 密鑰。此外,CLR Security 並沒有給我一種從X509Certificate2簽名驗證中獲取公鑰的方法(我什至沒有或不需要簽名者的私鑰)。

有任何想法嗎?我束手無策……任何幫助將不勝感激。

您需要從證書的公鑰 ( certificate.PublicKey.EncodedKeyValue.RawData) 創建 CngKey:

CngKey 包含 8 個附加字節,前 4 個字節(所謂的魔術)用於所用曲線的名稱(對於 ECDsa:ECS1、ECS3 或 ECS5,對於 ECDH:ECK1、ECK3、ECK5),最後 4 個是密鑰的長度,包括。填充(32、48 或 66)。

證書中公鑰的第一個字節被刪除(因為對於 ECDSA 公鑰,它始終為 0x04)。

因此,例如對於使用 P-256 曲線和 SHA-256 雜湊算法的 ECDSA,您將獲得長度為 65 字節的公鑰。丟棄第一個字節,留下 64 個字節,然後以 4 個字節作為曲線前綴和 4 個字節作為密鑰長度前綴,即:

var keyData = certificate.PublicKey.EncodedKeyValue.RawData.Skip(1).ToArray();
var keySize = BitConverter.GetBytes(keyData.Length/2);
var magic = Encoding.ASCII.GetBytes("ECS1").Concat()

var eccPublicBlobValue = magic.Concat(keySize).Concat(keyData).ToArray();

現在你有了公鑰(72 字節)來創建 CngKey:

var cngKey = CngKey.Import(eccPublicBlobValue, CngKeyBlobFormat.EccPublicBlob);

var ecdsaCng = new ECDsaCng(cngKey);

您可以驗證簽名:

return ecdsaCng.VerifyData(encodedBytes, signature);

引用自:https://stackoverflow.com/questions/22762380