当前位置: 首页 > 知识库问答 >
问题:

使用ECDSA x509证书的Diffie Hellman密钥交换

阳宗清
2023-03-14
private byte[] GetDerivedKey(X509Certificate2 publicCertificate, X509Certificate2 privateCertificate)
    {
        byte[] derivedKey;

        using (var privateKey = privateCertificate.GetECDsaPrivateKey())
        using (var publicKey = publicCertificate.GetECDsaPublicKey())
        {
            var privateParams = privateKey.ExportParameters(true);  //This line is failing
            var publicParams = publicKey.ExportParameters(false);

            using (var privateCng = ECDiffieHellmanCng.Create(privateParams))
            using (var publicCng = ECDiffieHellmanCng.Create(publicParams))
            {
                derivedKey = privateCng.DeriveKeyMaterial(publicCng.PublicKey);
            }
        }
        

        return derivedKey;
    }

因为这是我正在生成的一个自签名证书,所以我认为我做错了什么。

我首先创建一个根CA证书,并传入私钥来签署我的证书。

private X509Certificate2 CreateECSDACertificate(string certificateName,
        string issuerCertificateName,
        TimeSpan lifetime,
        AsymmetricKeyParameter issuerPrivateKey,
        string certificateFriendlyName = null)
    {
        // Generating Random Numbers
        var randomGenerator = new CryptoApiRandomGenerator();
        var random = new SecureRandom(randomGenerator);

        var signatureFactory = new Asn1SignatureFactory("SHA256WithECDSA", issuerPrivateKey, random);

        // The Certificate Generator
        var certificateGenerator = new X509V3CertificateGenerator();

        // Serial Number
        var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
        certificateGenerator.SetSerialNumber(serialNumber);

        // Issuer and Subject Name
        var subjectDistinguishedName = new X509Name($"CN={certificateName}");
        var issuerDistinguishedName = new X509Name($"CN={issuerCertificateName}");
        certificateGenerator.SetSubjectDN(subjectDistinguishedName);
        certificateGenerator.SetIssuerDN(issuerDistinguishedName);

        // Valid For
        var notBefore = DateTime.UtcNow.Date;
        var notAfter = notBefore.Add(lifetime);

        certificateGenerator.SetNotBefore(notBefore);
        certificateGenerator.SetNotAfter(notAfter);

        //key generation
        var keyGenerationParameters = new KeyGenerationParameters(random, _keyStrength);
        var keyPairGenerator = new ECKeyPairGenerator();
        keyPairGenerator.Init(keyGenerationParameters);
        var subjectKeyPair = keyPairGenerator.GenerateKeyPair();

        certificateGenerator.SetPublicKey(subjectKeyPair.Public);

        var certificate = certificateGenerator.Generate(signatureFactory);

        var store = new Pkcs12Store();
        var certificateEntry = new X509CertificateEntry(certificate);
        store.SetCertificateEntry(certificateName, certificateEntry);
        store.SetKeyEntry(certificateName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry });

        X509Certificate2 x509;

        using (var pfxStream = new MemoryStream())
        {
            store.Save(pfxStream, null, new SecureRandom());
            pfxStream.Seek(0, SeekOrigin.Begin);
            x509 = new X509Certificate2(pfxStream.ToArray());
        }

        x509.FriendlyName = certificateFriendlyName;

        return x509;
    }

.hasPrivateKey()方法返回true,我读到的这个值可能返回假阳性。

    [Test]
    public void CreateSelfSignedCertificate_AfterAddingToStore_CanBuildChain()
    {
        var result = _target.CreateSelfSignedCertificate(_subject, _issuer, TimeSpan.FromDays(356), _certificateFriendlyName, _issuerFriendlyName);

        _store.TryAddCertificateToStore(result.CertificateAuthority, _caStoreName, _location);
        _store.TryAddCertificateToStore(result.Certificate, _certStoreName, _location);

        var chain = new X509Chain
        {
            ChainPolicy =
            {
                RevocationMode = X509RevocationMode.NoCheck
            }
        };

        var chainBuilt = chain.Build(result.Certificate);

        if (!chainBuilt)
        {
            foreach (var status in chain.ChainStatus)
            {
                Assert.Warn(string.Format("Chain error: {0} {1}", status.Status, status.StatusInformation));
            }
        }

        Assert.IsTrue(chainBuilt, "Chain");
    }

共有1个答案

公羊英达
2023-03-14

好的。这是一个盲目的镜头,但在看了你的代码后,我注意到了两件事:

  • 创建PFX时,您设置了空密码。但是当您将PFX加载到X509Certificate2类中时,您使用了错误的构造函数。您应该使用一个带有password参数的password参数,并给它一个null
  • 当您将PFX加载到X509Certificate2类中时,您没有指定私钥是否应可导出。我认为这就是privateKey.exportParameters(true)给出异常的原因。您应该使用此构造函数并将null指定为密码

我以为是虫子。有可能是的。我们在X509Constructor中明确说明私钥应该是可导出的。我还使用了x509KeyStorageFlags.ephemeralKeyset x509KeyStorageFlags.exportable标志。但当我查看CngKey时,它将ExportPolicy设置为AllowExport而不是AllowPlainTextExport

在某种程度上是可以出口的。privatekey.key.export(cngkeyblobformat.opaqueTransportblob)工作。但PrivateKey.ExportParameters(true)没有。

我已经搜索了一个如何改变CNGKEY的ExportPolicy的解决方案。我发现这个问题帮助我改变了它。之后,exportParameters工作。

您的GetDerivedKey方法的固定版本是

private byte[] GetDerivedKey(X509Certificate2 publicCertificate, X509Certificate2 privateCertificate)
{
    byte[] derivedKey;

    using (var privateKey = privateCertificate.GetECDsaPrivateKey())
    using (var publicKey = privateCertificate.GetECDsaPublicKey())
    {
        var myPrivateKeyToMessWith = privateKey as ECDsaCng;

        // start - taken from https://stackoverflow.com/q/48542233/3245057 
        // make private key exportable:
        byte[] bytes = BitConverter.GetBytes((int)(CngExportPolicies.AllowExport | CngExportPolicies.AllowPlaintextExport));
        CngProperty pty = new CngProperty(NCryptExportPolicyProperty, bytes, CngPropertyOptions.Persist);
        myPrivateKeyToMessWith.Key.SetProperty(pty);
        // end - taken from https://stackoverflow.com/q/48542233/3245057

        var privateParams = myPrivateKeyToMessWith.ExportParameters(true);  //This line is NOT failing anymore
        var publicParams = publicKey.ExportParameters(false);

        using (var privateCng = ECDiffieHellmanCng.Create(privateParams))
        using (var publicCng = ECDiffieHellmanCng.Create(publicParams))
        {
            derivedKey = privateCng.DeriveKeyMaterial(publicCng.PublicKey);
        }
    }

    return derivedKey;
}
 类似资料:
  • 这与.NET/C#有关。假设PFX或PKCS#12文件中有一个证书+私钥(P521 ECC 1)。通过安装该证书(双击PFX或运行),我们已将该证书及其私钥加载到Windows证书存储中。我注意到,如果证书是兼容的(例如p521曲线),它将自动安装为CNG证书/密钥。

  • 我试图建立一个双向TSL连接到一个Web服务使用Java,我得到了一个pfx证书与一个私钥和3个证书的证书链。下面是使用Spring框架的java代码: 到目前为止,我得到了一个客户端你好和一个发送证书的服务器你好,我得到了一个找到的可信证书。然后有一个证书请求,它找不到任何证书 我已经将证书单独添加到lib/Security/cacerts中。似乎第一次证书交换发生在cacerts密钥存储库,因

  • 我想生成一个自签名的可信证书和一个csr,并用创建的可信证书对csr进行签名。我正在用keytool尝试它。在使用以下命令创建受信任证书的第一步中 keytool-list-v-keystore cert/test.keystore 使用上面的“genkey”命令创建的证书的条目类型为“privatekeyentry”,如何创建可信的证书条目?

  • null 大多数示例使用makecert或New-SelfSignedCertificate创建证书。在这种情况下,对于生产应用程序,自签名证书是否有问题?这仅供应用程序使用Azure Key Vault进行身份验证,客户机在浏览器中不会看到这一点。 如果在这种情况下,自签名证书仍然不受欢迎,那么从受信任的权威机构购买证书是否与购买SSL/TLS证书的过程相同?甚至是同一类型的证书吗?

  • 我正在尝试创建一个ARM模板,它可以使用透明数据加密(TDE)在Azure中部署SQL Enterprise VM,使用密钥库作为EKM。 我找到了如何通过密钥库启用TDE的示例,包括101 SQL KeyVault模板和SQL ARM规定,但在这两种情况下,它们只需要密钥库URL和访问凭据(AppID和Secret)。 鉴于以上所述,我试图将SQL指向我作为pfx文件导入到key Vault中的

  • 我正在尝试对现有API启用Azure密钥库证书。我们已经在Azure Key Vault帐户中拥有秘密和Azure Key Vault证书。下面是配置证书的代码: 在我的本地计算机上,我正确地导入了证书,其中包括下载pfx格式。