简体   繁体   English

.NET ECDiffieHellmanCng和BouncyCastle Core兼容协议

[英].NET ECDiffieHellmanCng and BouncyCastle Core compatible agreement

I have to make a Diffie Hellman agreement with a third party that communicates the public keys in the .NET ECDiffieHellmanCng XmlString format. 我必须与第三方签订Diffie Hellman协议,该协议以.NET ECDiffieHellmanCng XmlString格式传递公钥。 I cannot change their code. 我无法改变他们的代码。 What they send looks like this: 他们发送的内容如下:

<ECDHKeyValue xmlns="http://www.w3.org/2001/04/xmldsig-more#">
  <DomainParameters>
    <NamedCurve URN="urn:oid:1.3.132.0.35" />
  </DomainParameters>
  <PublicKey>
    <X Value="11" xsi:type="PrimeFieldElemType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
    <Y Value="17" xsi:type="PrimeFieldElemType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
  </PublicKey>
</ECDHKeyValue>

They generate that using typical .NET Framework code like this: 他们使用典型的.NET Framework代码生成它,如下所示:

using (ECDiffieHellmanCng dhKey = new ECDiffieHellmanCng())
{
    dhKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
    dhKey.HashAlgorithm = CngAlgorithm.Sha256;

    Console.WriteLine(dhKey.PublicKey.ToXmlString());
}

They expect to receive my public key in the same format. 他们希望以相同的格式接收我的公钥。 They use my public key like this: 他们使用我的公钥这样:

ECDiffieHellmanCngPublicKey pbkey = ECDiffieHellmanCngPublicKey.FromXmlString(xmlHere);

I work in .NET core 2.1. 我在.NET核心2.1中工作。 Unfortunately the ECDiffieHellmanCng classes and the like are currently not implemented in .NET core. 不幸的是,ECDiffieHellmanCng类等目前尚未在.NET核心中实现。 I thought I could use the BouncyCastle for .NET Core package for this: https://www.nuget.org/packages/BouncyCastle.NetCore/ I would assume these both implement the same standard and they would be compatible. 我认为我可以使用BouncyCastle for .NET Core包: https ://www.nuget.org/packages/BouncyCastle.NetCore/我认为这两者都实现了相同的标准并且它们是兼容的。

I know how to do the agreement completely with the bouncy castle, however it's not clear to me how to do that starting with the X and Y values in the xml that come out of the .NET ECDiffieHellmanCng and how to make sure I use compatible parameters. 我知道如何与充气城堡完全达成协议,但是我不清楚如何从.NET ECDiffieHellmanCng中出现的xml中的X和Y值开始,以及如何确保使用兼容参数。 It's also not clear to me how I get the X and Y values from the bouncy castle public key that I generate to send back to them. 我也不清楚如何从我生成的弹性城堡公钥中获取X和Y值以发回给他们。 It doesn't help that the bouncy castle for .net api is not exactly the same as the java api and the documentation is limited. 对.net api的充气城堡与java api不完全相同并且文档有限,这没有任何帮助。

Update 1: After reading some comments below, it appears indeed that the ECDiffieHellmanCng are partially implemented in .NET Core. 更新1:在阅读下面的一些评论之后,确实ECDiffieHellmanCng在.NET Core中部分实现了。 Most of the logic works but only ToXmlString and FromXmlString don't work. 大多数逻辑工作,但只有ToXmlString和FromXmlString不起作用。 That's ok, I can work around that. 没关系,我可以解决这个问题。 However I'm now running into a different problem. 但是我现在遇到了另一个问题。 The curve that the other side uses is oid:1.3.132.0.35. 另一方使用的曲线是oid:1.3.132.0.35。 However when I try to use this in .NET core, even with a basic example like this: 但是,当我尝试在.NET核心中使用它时,即使使用如下基本示例:

    using (ECDiffieHellman dhBob = ECDiffieHellman.Create(ECCurve.CreateFromValue("1.3.132.0.35")))
    {
        using (ECDiffieHellman dhAlice = ECDiffieHellman.Create(ECCurve.CreateFromValue("1.3.132.0.35")))
        {
            byte[] b = dhAlice.DeriveKeyMaterial(dhBob.PublicKey);

            byte[] b2 = dhBob.DeriveKeyMaterial(dhAlice.PublicKey);

            Console.WriteLine(b.SequenceEqual(b2));
        }
    }

Then I get this error: 然后我收到这个错误:

Unhandled Exception: System.PlatformNotSupportedException: The specified curve 'ECDSA_P521' or its parameters are not valid for this platform. ---> Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The parameter is incorrect
   at System.Security.Cryptography.CngKeyLite.SetProperty(SafeNCryptHandle ncryptHandle, String propertyName, Byte[] value)
   at System.Security.Cryptography.CngKeyLite.SetCurveName(SafeNCryptHandle keyHandle, String curveName)
   at System.Security.Cryptography.CngKeyLite.GenerateNewExportableKey(String algorithm, String curveName)
   at System.Security.Cryptography.ECCngKey.GenerateKey(ECCurve curve)
   --- End of inner exception stack trace ---
   at System.Security.Cryptography.ECCngKey.GenerateKey(ECCurve curve)
   at System.Security.Cryptography.ECDiffieHellman.Create(ECCurve curve)
   at TestCore.Program.Main(String[] args) 

The error message is not clear to me. 我不清楚错误消息。 Is that curve really not supported? 这条曲线真的不受支持吗? Or is something wrong in the parameters, but then what exactly? 或者参数有问题,但究竟是什么? It would surprise me if the curve is not supported because nistP521 curve is supported and according to this IBM document I found online they are the same: https://www.ibm.com/support/knowledgecenter/en/linuxonibm/com.ibm.linux.z.wskc.doc/wskc_r_ecckt.html 如果不支持曲线会让我感到惊讶,因为支持nistP521曲线,根据我在网上找到的IBM文档它们是相同的: https ://www.ibm.com/support/knowledgecenter/en/linuxonibm/com.ibm .linux.z.wskc.doc / wskc_r_ecckt.html

It looks like there's just an equivalence problem with the handling of these OIDs with ECDH (it's turning it into the Windows ECDSA name instead of the Windows ECDH name). 看起来使用ECDH处理这些OID只会出现等效问题(它将其转换为Windows ECDSA名称而不是Windows ECDH名称)。 You can solve it with something like 你可以用类似的东西解决它

private static ECCurve GetCurveByOid(string oidValue)
{
    switch (oidValue)
    {
        case "1.2.840.10045.3.1.7":
            return ECCurve.NamedCurves.nistP256;
        case "1.3.132.0.34":
            return ECCurve.NamedCurves.nistP384;
        case "1.3.132.0.35":
            return ECCurve.NamedCurves.nistP521;
    }

    return ECCurve.CreateFromValue(oidValue);
}

Thanks all for your help. 感谢你的帮助。 Eventually I wrote this code which works on .Net Core 2.1 and which is compatible with the .Net Framework To/FromXmlString: 最后我写了这个代码,它适用于.Net Core 2.1,并且与.Net Framework To / FromXmlString兼容:

        using (ECDiffieHellmanCng dhBob = new ECDiffieHellmanCng())
        {
            dhBob.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
            dhBob.HashAlgorithm = CngAlgorithm.Sha256;
            string xmlBob = ToXmlString(dhBob.PublicKey);
            //Console.WriteLine(xmlBob);

            using (ECDiffieHellmanCng dhAlice = new ECDiffieHellmanCng())
            {
                dhAlice.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
                dhAlice.HashAlgorithm = CngAlgorithm.Sha256;
                ECDiffieHellmanPublicKey keyBob = FromXmlString(xmlBob, dhAlice.KeySize);
                byte[] b = dhAlice.DeriveKeyMaterial(keyBob);


                string xmlAlice = ToXmlString(dhAlice.PublicKey);
                ECDiffieHellmanPublicKey keyAlice = FromXmlString(xmlAlice, dhBob.KeySize);
                byte[] b2 = dhBob.DeriveKeyMaterial(keyAlice);

                Console.WriteLine(b.SequenceEqual(b2));
            }
        }

public static string ToXmlString(ECDiffieHellmanPublicKey key)
{
    // the regular ToXmlString from ECDiffieHellmanPublicKey throws PlatformNotSupportedException on .net core 2.1
    ECParameters parameters = key.ExportParameters();
    return string.Format("<ECDHKeyValue xmlns='http://www.w3.org/2001/04/xmldsig-more#'><DomainParameters><NamedCurve URN='urn:oid:{0}' />" +
                         "</DomainParameters><PublicKey><X Value='{1}' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' />" +
                         "<Y Value='{2}' xsi:type='PrimeFieldElemType' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' /></PublicKey></ECDHKeyValue>",
        GetOid(parameters.Curve),
        new BigInteger(parameters.Q.X.Reverse().ToArray().Concat(new byte[] { 0 }).ToArray()).ToString(System.Globalization.CultureInfo.InvariantCulture), // watch out for big endian - little endian
        new BigInteger(parameters.Q.Y.Reverse().ToArray().Concat(new byte[] { 0 }).ToArray()).ToString(System.Globalization.CultureInfo.InvariantCulture));
}

public static ECDiffieHellmanPublicKey FromXmlString(string xml, int keySize)
{
    // the regular FromXmlString from ECDiffieHellmanPublicKey throws PlatformNotSupportedException on .net core 2.1
    XDocument doc = XDocument.Parse(xml);
    XNamespace nsSys = "http://www.w3.org/2001/04/xmldsig-more#";
    string xString = doc.Element(nsSys + "ECDHKeyValue").Element(nsSys + "PublicKey").Element(nsSys + "X").Attribute("Value").Value;
    string yString = doc.Element(nsSys + "ECDHKeyValue").Element(nsSys + "PublicKey").Element(nsSys + "Y").Attribute("Value").Value;
    string curve = doc.Element(nsSys + "ECDHKeyValue").Element(nsSys + "DomainParameters").Element(nsSys + "NamedCurve").Attribute("URN").Value;
    curve = curve.Replace("urn:", "").Replace("oid:", "");

    byte[] arrayX = BigInteger.Parse(xString, System.Globalization.CultureInfo.InvariantCulture).ToByteArray(false, true); // watch out for big endian - little endian
    byte[] arrayY = BigInteger.Parse(yString, System.Globalization.CultureInfo.InvariantCulture).ToByteArray(false, true);

    // make sure each part has the correct and same size
    int partSize = (int) Math.Ceiling(keySize / 8.0);
    ResizeRight(ref arrayX, partSize);
    ResizeRight(ref arrayY, partSize);

    ECParameters parameters = new ECParameters() { Q = new ECPoint() { X = arrayX, Y = arrayY }, Curve = GetCurveByOid(curve) };
    ECDiffieHellman dh = ECDiffieHellman.Create(parameters);
    return dh.PublicKey;
}

/// <summary>
/// Resize but pad zeroes to the left instead of to the right like Array.Resize
/// </summary>
public static void ResizeRight(ref byte[] b, int length)
{
    if (b.Length == length)
        return;
    if (b.Length > length)
        throw new NotSupportedException();

    byte[] newB = new byte[length];
    Array.Copy(b, 0, newB, length - b.Length, b.Length);
    b = newB;
}

private static ECCurve GetCurveByOid(string oidValue)
{
    // there are strange bugs in .net core 2.1 where the createfromvalue doesn't work for the named curves
    switch (oidValue)
    {
        case "1.2.840.10045.3.1.7":
            return ECCurve.NamedCurves.nistP256;
        case "1.3.132.0.34":
            return ECCurve.NamedCurves.nistP384;
        case "1.3.132.0.35":
            return ECCurve.NamedCurves.nistP521;
        default:
            return ECCurve.CreateFromValue(oidValue);
    }
}

private static string GetOid(ECCurve curve)
{
    // there are strange bugs in .net core 2.1 where the value of the oid of the named curves is empty
    if (curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP256.Oid.FriendlyName)
        return "1.2.840.10045.3.1.7";
    else if (curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP384.Oid.FriendlyName)
        return "1.3.132.0.34";
    else if (curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP521.Oid.FriendlyName)
        return "1.3.132.0.35";
    else
        return curve.Oid.Value;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么BouncyCastle生成的密钥比.Net的ECDiffieHellmanCng小 - Why Does BouncyCastle Generate Keys Smaller Than .Net's ECDiffieHellmanCng .Net Core 2.0 与.Net Core 2.1 兼容 - .Net Core 2.0 compatible with .Net Core 2.1 我的 NuGet 包是否与 .NET Core 兼容? - Are my NuGet packages compatible with .NET Core? Azure Notification Hubs程序包是否与.NET Core兼容? - Is Azure Notification Hubs package compatible with .NET Core? Bouncy Castle ECDH和.net4原生ECDiffieHellmanCNG之间的区别 - Difference between Bouncy Castle ECDH and the .net4 native ECDiffieHellmanCNG BouncyCastle 部署错误:HTTP 错误 500.30 - ASP.NET 核心应用程序无法启动 - BouncyCastle deployment error: HTTP Error 500.30 - ASP.NET Core app failed to start 在.NET Core中以跨平台兼容的方式删除文件 - Deleting files in a cross platform compatible manner in .NET Core .net-core 2.2 与 windows server 2008 sp2 兼容吗? - Is .net-core 2.2 compatible with windows server 2008 sp2? Serilog 关联日志消息 package 与 asp.net 内核不兼容 - Serilog Correlate Log Messages package not compatible with asp.net core 如何将 JSON 字符串转换为与 xUnit/.NET Core API 兼容的 object? - How to convert JSON string to object compatible with xUnit/.NET Core API?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM