I need to use elliptic curve Diffie Hellman between a ARM cortex M3 and the PC. On the ARM, I use mbed TLS. On the PC side I want to us C# and the ECDiffieHellman(Cng) class.
I can do the ECDH on ARM vs ARM, but I do have trouble when I try to replace one side with the PC.
<LEN><0x04><X><Y>
.Thus, In C# I am importing the public key using
private static EC
DiffieHellmanPublicKey ToPublicKey(byte[] publicKey)
{
var keyLength = 32;
if (publicKey[0] != (2 + 2 * keyLength) - 1)
throw new ArgumentException("Invalid key length", nameof(publicKey));
if (publicKey[1] != 0x04)
throw new ArgumentException("Invalid key format", nameof(publicKey));
var parameters = new ECParameters()
{
Curve = ECCurve.NamedCurves.brainpoolP256r1,
Q = new ECPoint()
{
X = publicKey.Skip(2).Take(keyLength).ToArray(),
Y = publicKey.Skip(2 + keyLength).Take(keyLength).ToArray()
}
};
using (var tmp = ECDiffieHellman.Create(parameters))
{
return tmp.PublicKey;
}
}
var ecdh = new ECDiffieHellmanCng(ECCurve.NamedCurves.brainpoolP256r1);
ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Tls;
ecdh.Seed = new byte[32];
ecdh.Label = Encoding.ASCII.GetBytes("ECDiffieHellman");
new RNGCryptoServiceProvider().GetBytes(ecdh.Seed);
// ...
var sharedSecret = ecdh.DeriveKeyMaterial(peersPublicKey);
My problem is that the generated shared secret is of different length compared to the one generated by mbed TLS and does not match.
Did someone already solve this problem?
Thanks!
EDIT 1:
I forgot to mention, that I use bare ECDH on ARM. So I don't think there is any key derivation function executing. Is it sufficient to hash (SHA256) the result to match the C# side (when configuring SHA256 as KDF there)?
I solved the problem. In short: just hash the ECDH result.
C/C++ side:
mbedtls_ecdh_init(...);
mbedtls_ecdh_setup(...);
mbedtls_ecdh_make_public(...); //make own public key and send it to peer
mbedtls_ecdh_read_public(...); //reed peers public key
mbedtls_ecdh_calc_secret(...); //note: i pass in my own RND func because of no OS
mbedtls_ecdh_free(...);
mbedtls_sha256_init(...);
mbedtls_sha256_starts_ret(...);
mbedtls_sha256_update_ret(...);
mbedtls_sha256_finish_ret(...);
mbedtls_sha256_free(...);
C# side:
private void EllipticCurveDiffieHellman()
{
var ecdh = new ECDiffieHellmanCng(ECCurve.NamedCurves.brainpoolP256r1);
ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdh.HashAlgorithm = CngAlgorithm.Sha256;
//get relevant point from own public key
var ownPublicKey = ecdh.PublicKey.ExportExplicitParameters().Q;
var peersPublicKey = SendPublicKey(ownPublicKey); //key exchange
var sharedSecret = ecdh.DeriveKeyMaterial(peersPublicKey);
Console.WriteLine("Key: " + HexValue.Parse(sharedSecret.ToArray()));
}
DiffieHellmanPublicKey ToPublicKey(byte[] publicKey)
{
var keyLength = 32;
if (publicKey[0] != (2 + 2 * keyLength) - 1)
throw new ArgumentException("Invalid key length", nameof(publicKey));
if (publicKey[1] != 0x04)
throw new ArgumentException("Invalid key format", nameof(publicKey));
var parameters = new ECParameters()
{
Curve = ECCurve.NamedCurves.brainpoolP256r1,
Q = new ECPoint()
{
X = publicKey.Skip(2).Take(keyLength).ToArray(),
Y = publicKey.Skip(2 + keyLength).Take(keyLength).ToArray()
}
};
using (var tmp = ECDiffieHellman.Create(parameters))
{
return tmp.PublicKey;
}
}