Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
511 views
in Technique[技术] by (71.8m points)

c# - Import a Public key from somewhere else to CngKey?

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 crypto libraries, but then I couldn't figure out how a 33 (or 65) byte public key (using secp256r1/P256) was getting turned into 104 bytes by MS.. Ergo, I couldn't support cross platform signing and verifying..

I'm using BouncyCastle now, but holy handgranade is it SLOW!

So, looking for suggestions for the following requirements:

  1. Cross platform/Languages (server is .NET, but this is served up via a JSON/Web.API interface)
    • JavaScript, Ruby, Python, C++ etc..
  2. Not crazy as slow on the server
  3. Not so painfully slow people can't use it on the client.

The client has to be able to sign the message, the server has to be able to validate the signature with a public key that was exchanged at registration to the service.

Anyways, Ideas would be awesome... Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

  • [KEY TYPE (4 bytes)][KEY LENGTH (4 bytes)][PUBLIC KEY (64 bytes)][PRIVATE KEY (32 Bytes)]
  • KEY TYPE in HEX is 45-43-53-32
  • KEY LENGTH in HEX is 20-00-00-00
  • PUBLIC KEY is the uncompressed format minus the leading byte (which is always 04 to signify an uncompressed key in other libraries)

ECCPublicKeyBlob is formatted (for P256) as follows

  • [KEY TYPE (4 bytes)][KEY LENGTH (4 bytes)][PUBLIC KEY (64 bytes)]
  • KEY TYPE in HEX is 45-43-53-31
  • KEY LENGTH in HEX is 20-00-00-00
  • PUBLIC KEY is the uncompressed format minus the leading byte (which is always 04 to signify an uncompressed key in other libraries)

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,
    ...
    ...
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...