Search code examples
c#encryptioncng

Building a private CngKey(ECDH_P384) from a passphrase


Context: VS 2015 winforms, Windows 7, using SecurityDriven Inferno library.

I'm coding an offline app which produces encrypted files to be sent as email attachments (thus not used in a client-server context). The files are first encrypted with Inferno(ETM_Transform), then sent with (sometimes, to reset password) another file, handling DHM key exchange.

The public key of each user is stored in a datatable created and persisted by the app, allowing quick access during key exchange process. For the private key, however, my problem is that the users (including myself) would prefer to recreate their private key from a pass phrase, eliminating the need to hide the key away, increasing security and portability. So I would need to build a key from the stored public key and the hashed pass phrase.

Is this a sound approach or perhaps there's a better one for this specific context?

Here is a very short code example which throws the exception: "The requested operation is not supported". How should I proceed to import the data into the key?

    internal static void CreateKey(string passPhrase)
    {
        byte[] keyType = new byte[] { 0x45, 0x43, 0x4B, 0x34 };
        byte[] keyLength = new byte[] { 0x30, 0x0, 0x0, 0x0 };            

        CryptoRandom cr = new CryptoRandom(); // rng used for this example
        byte[] prKey = cr.NextBytes(48); // salt+hash passphrase and pass it to the private key part
        byte[] pbKey = cr.NextBytes(96); // the public part, if I understand the format correctly for a cngkey using ECDH_P384
        byte[] blob = Utils.Combine(keyType, keyLength); // same as concat
        blob = Utils.Combine(blob, pbKey, prKey);

        CngKey key = CngKey.Import(blob, CngKeyBlobFormat.EccPrivateBlob);                        
    }

Solution

  • You can't randomly generate the public key. The public key is calculated from the private key (and the curve), and you are likely getting an error that a) the public X does not match what is expected from the private key, and b) that the Y coordinate is incorrect for the given X coordinate.

    You would need to compute the value of a public key from your chosen private key. As far as I know, neither .Net nor Windows CNG expose that functionality.