ECDiffieHellmanPublicKey from ByteArray (using ECD

2019-08-24 10:30发布

问题:

I'm working on communication nodejs -> c# server. I need to secure connection between them so I chode ECDiffieHellman as the key exchange mechanism (nodejs supports it). I had some problem with it... Just my lack of knowledge so I've made my lesson and now I can generate and export keys as base64 and nodejs have no problem with accepting c# key but on the other side c# ... won't even take his own key ... error System.Security.Cryptography.CryptographicException: 'The parameter is incorrect.' Ye I know I'm making sth wrong but what?

using (ECDiffieHellman alice = ECDiffieHellman.Create(ECCurve.NamedCurves.brainpoolP256r1))
{

    var alicePublicKey = Convert.ToBase64String(alice.PublicKey.ToByteArray());
    //NODEJS brainpoolP256r1 publickey 
    var key1 = Convert.FromBase64String("BB92GQLod55fXEhgNxwQcPQFFvph7eIjnSzdNz2PhzUAOcaPEiLBPQR6AL5pqVLFram8OtPapoBGYZn2vaGl+/U=").ToList();
    //test
    var key2 = Convert.FromBase64String(alicePublicKey);
    var keyType = new byte[] { 0x45, 0x43, 0x4B, 0x50 };
    var keyLength = new byte[] { 0x20, 0x00, 0x00, 0x00 };
    key1.RemoveAt(0);
    key1 = keyType.Concat(keyLength).Concat(key1).ToList();
    byte[] bobKeyBytes = key1.ToArray();
    ECDiffieHellmanPublicKey k = ECDiffieHellmanCngPublicKey.FromByteArray(bobKeyBytes, new CngKeyBlobFormat("ECCPUBLICBLOB")); //error  System.Security.Cryptography.CryptographicException: 'The parameter is incorrect.'
    ECDiffieHellmanPublicKey kk = ECDiffieHellmanCngPublicKey.FromByteArray(key2, new CngKeyBlobFormat("ECCPUBLICBLOB")); // error System.Security.Cryptography.CryptographicException: 'The parameter is incorrect.'
    byte[] aliceKey = alice.DeriveKeyMaterial(k);
    byte[] encryptedMessage = null;
    byte[] iv = null;
    // Send(aliceKey, "Secret message", out encryptedMessage, out iv);
}

you can find rest of the story there ECDH nodejs and C# key exchange

回答1:

You're asserting that the base64 contents that go into key1 are for brainpoolP256r1.

Decoding the value we see that it's a 65 byte payload starting with 04, which looks like an uncompressed point encoding for a curve with a 256-bit prime. So far so good.

You've even correctly used BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC, but you can't import a "generic named key blob" without specifying the import property that tells it which curve.

The easy way that you load the key from this point is

byte[] keyX = new byte[key1.Length / 2];
byte[] keyY = new byte[keyX.Length];
Buffer.BlockCopy(key1, 1, keyX, 0, keyX.Length);
Buffer.BlockCopy(key1, 1 + keyX.Length, keyY, 0, keyY.Length);

ECParameters parameters = new ECParameters
{
    Curve = ECCurve.NamedCurves.brainpoolP256r1,
    Q =
    {
        X = keyX,
        Y = keyY,
    },
};

byte[] derivedKey;

using (ECDiffieHellman bob = ECDiffieHellman.Create(parameters))
using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
{
    derivedKey = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA256);
}

I've gone ahead and expanded the DeriveKeyMaterial method into what it means by default with an ECDiffieHellmanCng, since other types of ECDH don't support that method (due to its low specificity of behavior).