1

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.

M. Altmann
  • 726
  • 5
  • 20
  • 3
    Binary data cannot usually be converted to a UTF-8 encoded string. Have you tried Base64 or Hex instead? – Artjom B. Mar 07 '17 at 20:31
  • My fault. Before converting to UTF-8 I've compared the first bytes of the public keys and they where the same - but you are right. Converting to Base64 shows different keys after the 13th digit. Thanks a lot! – M. Altmann Mar 07 '17 at 20:44

1 Answers1

5

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.

bartonjs
  • 30,352
  • 2
  • 71
  • 111