I want to implement Curve25519 as an ECCurve type so that it can be used in ECDsa. I've tried to define as shown below:
public class Curves
{
// TODO: check the key gen rand. work in progress. check constants.
public static ECCurve Curve25519
{
get
{
return new ECCurve()
{
CurveType = ECCurve.ECCurveType.PrimeMontgomery,
B = new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
A = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,109,6},
G = new ECPoint()
{
X = new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9},
Y = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }},
Prime = new byte[] { 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 237 },
Order = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8},
Cofactor = new byte[] { 1 }, // fix later
};
}
}
and later call
var ecc2 = ECDsa.Create(Curves.Curve25519);
This throws a null pointer exception, which does not make any sense to me. When we call the Validate method on the curve, everything seems to works.
What is the reason behind this null pointer exception?
Do you have a stack trace?
Test Name: TestMethod1
Test FullName: UnitTestProject1.UnitTest1.TestMethod1
Test Source: C:\Users\User\Documents\GitHub\ECC-in-dot-NET\ECCSafeCurves\UnitTestProject1\UnitTest1.cs : line 16
Test Outcome: Failed
Test Duration: 0:00:00.2012375
Result StackTrace:
at System.Security.Cryptography.ECCurve.get_Oid()
at System.Security.Cryptography.ECDsa.Create(ECCurve curve)
at UnitTestProject1.UnitTest1.TestMethod1() in C:\Users\User\Documents\GitHub\ECC-in-dot-NET\ECCSafeCurves\UnitTestProject1\UnitTest1.cs:line 21
Result Message:
Test method UnitTestProject1.UnitTest1.TestMethod1 threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
It looks like ECDsa.Create(ECCurve) on Windows ended up with a named curve bias.
C#
private static void ECDsaCreate(ECCurve curve)
{
var ecdsa = ECDsa.Create();
ecdsa.GenerateKey(curve);
return ecdsa;
}
That should work (based solely on code inspection).
I've tested the code suggestion and got the error below:
By executing the code:
var ecdsa = ECDsa.Create();
ecdsa.GenerateKey(Curves.Curve25519);
I get the following:
Result StackTrace:
at System.Security.Cryptography.CngKeyLite.SetProperty(SafeNCryptHandle ncryptHandle, String propertyName, Byte[] value)
at System.Security.Cryptography.CngKeyLite.GenerateNewExportableKey(String algorithm, ECCurve& explicitCurve)
at System.Security.Cryptography.ECDsaImplementation.ECDsaCng.GenerateKey(ECCurve curve)
at UnitTestProject1.UnitTest1.TestMethod1() in C:\Users\User\Documents\GitHub\ECC-in-dot-NET\ECCSafeCurves\UnitTestProject1\UnitTest1.cs:line 22
Result Message:
Test method UnitTestProject1.UnitTest1.TestMethod1 threw exception:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The requested operation is not supported
Windows doesn't support explicit curves until Windows 10. That callstack makes me think you're on something older. There's not really a workaround for that, since there's just not OS support for us to call into.
I'm using Windows 10 Pro and the project is targeting _.NETCoreApp1.1_
Okay... Hm. With your curve definition I replicate your exception. With NIST P-256 explicit I get success.
C#
// SEC2-Ver-1.0, 2.7.2
return new ECCurve
{
CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
Prime = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF".HexToByteArray(),
A = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC".HexToByteArray(),
B = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B".HexToByteArray(),
Seed = "C49D360886E704936A6678E1139D26B7819F7E90".HexToByteArray(),
Hash = HashAlgorithmName.SHA1,
G = new ECPoint
{
X = "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296".HexToByteArray(),
Y = "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5".HexToByteArray(),
},
Order = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551".HexToByteArray(),
Cofactor = new byte[] { 0x01 },
};
I think part of the problem is that your curve parameters are wrong. Like, G.Y seems rather incorrect. And if the curve order were 8 there'd only be 8 private keys, which seems pretty easy to brute force :smile:.
Now that I'm a little more awake I feel like Windows has limited Montgomery curve support. In particular, I think that they're only valid for keys created with a purpose of ECDiffieHellman. So maybe what it's saying is that it doesn't like the Montgomery curve curvetype for ECDH. You could try the Edwards equivalent (https://en.wikipedia.org/wiki/Montgomery_curve#Equivalence_with_twisted_Edwards_curves), or the short Weierstrass equivalent.
Since the issue started off about ECDsa.Create(ExplicitCurve) encountering a NullReferenceException and I've fixed that, I'm going to close the issue. Feel free to keep posting on your progress, and we can make new issues for specific faults as they're encountered.
Though I am a bit curious why you're wanting to do ECDsa with curve25519; it's self-described for ECDH:
Curve25519 is a state-of-the-art Diffie-Hellman function suitable for a wide variety of applications.
(https://cr.yp.to/ecdh.html)
@bartonjs I used it just to test ECC in .NET. Thank you for pointing this out. It appears there is no ECDH handler in .NET core. It would be cool if .NET Core would support some of the safe curves here: https://safecurves.cr.yp.to/. Maybe in a future release?
Did anyone succeed in making Curve25519 work with .netcore/standard?
@bartonjs I know that this issue is closed, but I'm wondering if you have insight into the correct ECCurve definition for Curve25519 in an ECDH context. You had previously pointed out that @artemlos used an incorrect Order in his solution.
@adamjstone https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186-draft.pdf 4.2.2.1
@bartonjs This is slightly off topic, but I'm trying to figure out which platforms are not supported for the CNG APIs in a .NET Standard contexts. I see that numerous types (eg. CngKey) raise PlatformNotSupportedException but the documentation doesn't specify which platforms are explicitly supported. Thanks!
@adamjstone CNG works on Windows, and nowhere else.
@bartonjs Follow-up question. My understanding is that ECDiffieHellman.Create() produces an instance of an ECDiffieHellmanCng. The documentation does not indicate that a PlatformNotSupportedException is raised for .NET Standard, though. Using .NET Standard, what is the behavior for, say, Linux environments? Is there another implementation of ECDiffieHellman somewhere in the runtime source?
Another follow-up question, @bartonjs (please excuse me). What I'm trying to accomplish is probably obvious. If it is the case that the elliptic curve APIs are not cross-platform when using .NET Standard, should I bite the bullet and use a third party package or will I kick myself in the near future when a .NET revision introduces cross-platform support? Thanks for the intel.
@adamjstone ECDiffieHellman.Create() returns a platform-appropriate instance of an ECDiffieHellman-derived type. For best results, don't ever cast it to a more specific type, just use the methods available on the ECDiffieHellman base class. (Similar for RSA.Create(), ECDsa.Create(), and (NS2.1) DSA.Create() -- and all the symmetric algorithms: Aes.Create(), TripleDES.Create(), etc).
The platform-specific types (ECDiffieHellmanCng, ECDiffieHellmanOpenSsl) are only for doing specific platform interop: opening named keys, using keys from pointers returned by other libraries, etc. If you're just using algorithms, don't go past the algorithm types, and everything works great.
Absolutely understood, Jeremy. Wasn't planning any such abuses of the type system or the APIs, was just worried that customers on Linux servers were going to get exceptions. I couldn't tell from the documentation that there was any implementation other than CNG. Very much appreciate you taking time to answer my questions.