gpt4 book ai didi

c# - 在 C# 中使用 ECDSA 生成证书

转载 作者:行者123 更新时间:2023-11-30 14:50:28 26 4
gpt4 key购买 nike

我正在尝试使用 ECDSA 生成带有私钥的(自签名)证书。目标是获得与使用 openssl 时“相同的”(pkcs12) 证书:

openssl ecparam -genkey -name secp256r1 -out mykey.key
openssl req -new -key mykey.key -out myreq.csr
openssl req -x509 -days 7 -key mykey.key -in myreq.csr -out mycert.crt
openssl pkcs12 -export -out mycert.pfx -inkey mykey.key -in mycert.crt

我已经使用 BouncyCaSTLe 来帮助我创建基于 RSA 的证书,所以接下来的步骤或多或少地遵循我用来创建 RSA 证书的方式。

(注意 BC 前缀用于 BouncyCaSTLe 的类,MS 用于 .NET 类)

1生成 key 对:私钥和公钥

BC.IAsymmetricCipherKeyPairGenerator bcKpGen = BC.GeneratorUtilities.GetKeyPairGenerator("ECDSA");
bcKpGen.Init(new BC.ECKeyGenerationParameters(BC.SecObjectIdentifiers.SecP256r1, new BC.SecureRandom()));
BC.AsymmetricCipherKeyPair bcSubjKeys = bcKpGen.GenerateKeyPair();

2使用私钥和一些附加数据(主题、有效期等)对公钥进行签名

BC.X509V3CertificateGenerator bcXgen = new BC.X509V3CertificateGenerator();
// .. set subject, validity period etc
bcXgen.SetPublicKey(bcSubjKeys.Public);
BC.ISignatureFactory bcSigFac = new BC.Asn1SignatureFactory("SHA256WITHECDSA", bcSubjKeys.Private);
BC.X509Certificate bcCert = bcXgen.Generate(bcSigFac);

3“加入”来自第 1 步的私钥和来自第 2 步的证书以获得带有私钥的证书。

如果我可以接受没有私钥的证书,我可以这样做:

MS.X509Certificate mcCert = new MS.X509Certificate2(bcCert.GetEncoded(), null);

我完成了。

尝试设置私钥时出现问题:

msCert.PrivateKey = ConvertBouncyToNetSomehow(bcSubjKeys.Private)

(注意 typeof msCert.PrivateKeyMS.AsymmetricAlgorithmbcSubjKeys.Private 的类型是 BC.ECPrivateKeyParameters )

似乎合适的方法是使用 MS.ECDsaCng类(继承自 MS.AsymmetricAlgorithm ),但是:

1 我发现转换 BC.ECPrivateKeyParameters 的唯一方法至 MS.CngKey (MS.ECDsaCng 要求)通过 pkcs8 格式:

BC.PrivateKeyInfo bcPKInfo = BC.PrivateKeyInfoFactory.CreatePrivateKeyInfo(bcSubjKeys.Private);
byte[] pkArr = bcPKInfo.GetDerEncoded();
MS.CngKey msPKCng = MS.CngKey.Import(pkArr, MS.CngKeyBlobFormat.Pkcs8PrivateBlob);

但是使用这种方法会丢失一些信息,因为 msPKCng.AlgorithmGroup 的值是"ECDH"同时bcSubjKeys.Private.AlgorithmName"ECDSA" . ECDH key 也不能与 MS.ECDsaCng 一起使用.

尽管如此..我可以继续MS.ECDiffieHellmanCng而不是请求 MS.ECDsaCng如果……

2 实现MS.X509Certificate2.set_PrivateKey要求对象实现接口(interface) MS.ICspAsymmetricAlgorithm .但它们( ECDsaCngECDiffieHellmanCng )都没有实现它。

此时似乎必须使用不同的方法(因为 MS.ICspAsymmetricAlgorithm 条件),例如将证书和私钥导出到 pkcs 文件并使用 X509Certificate2.Import(..) .

有什么提示吗?问候

最佳答案

不幸的是,现在不可能直接开箱即用。您可以使用 P/Invokes 和 .NET 4.6.2(目前处于预览阶段)完成剩下的工作。或者,绕过 .NET Core,您可以构建可在 .NET 4.6.1 中运行的 PFX。

“ECDSA”与“ECDH”

Windows CNG 库将 ECC 分为 ECDSA 和 ECDH。 ECDSA key 对象只能用于ECDSA;但每当 Windows 在 PFX 导入(或 PKCS#8 导入)期间无法确定使用情况时,它就会调用私钥 ECDH。为什么?因为Windows让ECDH key 对象同时做 key 协商(ECDH)和数字签名(ECDSA),所以ECDH更加灵活。

但是 .NET 4.6.1 不知道这一点。

.NET Core 没有此限制(参见 https://github.com/dotnet/corefx/pull/5850 ),.NET 4.6.2 也删除了该限制(根据 https://github.com/Microsoft/dotnet/blob/master/releases/net462/dotnet462-changes.md#user-content-bcl )。

生成“ECDSA” key ,而不是“ECDH”

.NET Core 现在有一个 ImportParameters ECDsa 上的方法。如果可以将 BC.ECPrivateKeyProperty 对象转换为 MS.ECParameters 结构,则可以将 blob 导入 ECDsaCng 对象。 (一定要将其用作命名曲线,而不是显式复制所有曲线参数)。

由于它是有意导入到 ECDsa 对象中的,因此它会获得一个 ECDSA key ,并且该信息将嵌入到 PFX 中。

构建 PFX(将它们捆绑在一起)

通过一些 P/Invoking,您可以说服 Windows 使用临时 key 构建 PFX。虽然 .NET 无法从证书访问临时私钥,但如果从 PFX 加载,它将能够使用它:

[DllImport(Libraries.Crypt32, CharSet = CharSet.Unicode, SetLastError = true)]
private static extern unsafe bool CertSetCertificateContextProperty(IntPtr pCertContext, CertContextPropId dwPropId, CertSetPropertyFlags dwFlags, SafeNCryptKeyHandle pvData);

internal enum CertContextPropId : int
{
CERT_NCRYPT_KEY_HANDLE_PROP_ID = 78,
}

[Flags]
internal enum CertSetPropertyFlags : int
{
None = 0,
}

private static X509Certificate2 MateECDsaPrivateKey(
X509Certificate2 cert,
CngKey privateKey)
{
// Make a new certificate instance which isn't tied to the current one
using (var tmpCert = new X509Certificate2(cert.RawData))
{
SafeNCryptKeyHandle keyHandle = privateKey.Handle;

// Set the ephemeral key handle property
if (!CertSetCertificateContextProperty(
tmpCert.Handle,
CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID,
CertSetPropertyFlags.None,
keyHandle))
{
throw new CryptographicException(Marshal.GetLastWin32Error());
}

// You could emit this, if you prefer.
byte[] pfxBytes = tmpCert.Export(X509ContentType.Pkcs12);

// Clear the key handle out again to prevent double-free
keyHandle = new SafeNCryptKeyHandle();

if (!CertSetCertificateContextProperty(
tmpCert.Handle,
CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID,
CertSetPropertyFlags.None,
keyHandle))
{
throw new CryptographicException(Marshal.GetLastWin32Error());
}

// Now load a new certificate which has a temporary keyfile on disk.
// Note: If you don't want exportability here, don't request it.
var matedCert = new X509Certificate2(pfxBytes, (string)null, X509KeyStorageFlags.Exportable);

using (ECDsa ecdsa = matedCert.GetECDsaPrivateKey())
{
if (ecdsa == null)
{
throw new InvalidOperationException("It didn't work");
}
}

return matedCert;
}
}

您需要 .NET 4.6.1(或更新版本)才能访问 GetECDsaPrivateKey()。

关于c# - 在 C# 中使用 ECDSA 生成证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36624105/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com