Reputation: 726
I'm playing around with the C# ECDiffieHellmanCng class and found a (in my opinion strange) behavior using the code from the sample: Every generated public key in any project ist the same! Is this correct and a desired behavior?
Example:
using (ECDiffieHellmanCng bob = new ECDiffieHellmanCng())
{
bob.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
bob.HashAlgorithm = CngAlgorithm.Sha256;
Trace.WriteLine(Encoding.UTF8.GetString(bob.PublicKey.ToByteArray()));
}
The trace will always have "ECK5B" as output. Using a different constructor will only differ the output a bit but not the fact, that it is always the same. Do I missunderstand something and this result is as expected and there is no chance to provide a random public key? I just thought the system would use some more randomness.
Upvotes: 1
Views: 888
Reputation: 33088
The ToByteArray()
method, returns the (Windows-specific) CNG blob describing the key.
The blob layout is
UINT32 Magic
UINT32 cbKey
<cbKey bytes of public key>
the value for BCRYPT_ECDH_PUBLIC_P521_MAGIC
is 0x354B4345
, which if viewed in Little-Endian order (45 43 4B 35
) is the ASCII string ECK5
. The x
coordinate of a point on the NIST P-521 curve needs up to 521 bits, or ((521+7)/8) == 66 bytes. (UINT32)66
in Little-Endian is 42 00 00 00
. So all of the byte arrays (for a NIST P-521-based public key) will start with
45 43 4B 35 42 00 00 00
(and then have 66 more bytes of the X component of the ECPoint). Since the ASCII string will terminate when it reads the first 0x00
, this gets interpreted (as a string) as ECK5B
.
As you've already discovered, this value isn't actually a string, so in order to be treated as one it needs to be encoded to a string-safe format, such as hex or Base64. Since hex is a 1=>2 encoding (or 1=>~3 with spaces) and Base64 is a 3=>4 encoding, most applications end up using Base64.
Upvotes: 5