I am looking for a cross platform way to share public keys for ECDSA signing. I had a great thing going from a performance perspective with CngKey and the standard .NET cry
So I have figured out the format of a CngKey exported in ECCPublicKeyBlob and ECCPrivateKeyBlob. This should allow others to interop between other key formats and CngKey for Elliptcal Curve signing and such.
ECCPrivateKeyBlob is formatted (for P256) as follows
ECCPublicKeyBlob is formatted (for P256) as follows
So given a uncompressed Public key in Hex from another language, you can trim the first byte, add those 8 bytes to the front and import it using
CngKey.Import(key,CngKeyBlobFormat.EccPrivateBlob);
Note: The key blob format is documented by Microsoft.
The KEY TYPE and KEY LENGTH are defined in BCRYPT_ECCKEY_BLOB struct as:
{ ulong Magic; ulong cbKey; }
ECC public key memory format:
BCRYPT_ECCKEY_BLOB
BYTE X[cbKey] // Big-endian.
BYTE Y[cbKey] // Big-endian.
ECC private key memory format:
BCRYPT_ECCKEY_BLOB
BYTE X[cbKey] // Big-endian.
BYTE Y[cbKey] // Big-endian.
BYTE d[cbKey] // Big-endian.
The MAGIC values available in .NET are in Microsoft's official GitHub dotnet/corefx BCrypt/Interop.Blobs.
internal enum KeyBlobMagicNumber : int
{
BCRYPT_ECDH_PUBLIC_P256_MAGIC = 0x314B4345,
BCRYPT_ECDH_PRIVATE_P256_MAGIC = 0x324B4345,
BCRYPT_ECDH_PUBLIC_P384_MAGIC = 0x334B4345,
BCRYPT_ECDH_PRIVATE_P384_MAGIC = 0x344B4345,
BCRYPT_ECDH_PUBLIC_P521_MAGIC = 0x354B4345,
BCRYPT_ECDH_PRIVATE_P521_MAGIC = 0x364B4345,
BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345,
BCRYPT_ECDSA_PRIVATE_P256_MAGIC = 0x32534345,
BCRYPT_ECDSA_PUBLIC_P384_MAGIC = 0x33534345,
BCRYPT_ECDSA_PRIVATE_P384_MAGIC = 0x34534345
BCRYPT_ECDSA_PUBLIC_P521_MAGIC = 0x35534345,
BCRYPT_ECDSA_PRIVATE_P521_MAGIC = 0x36534345,
...
...
}