views:

19

answers:

1

I'm trying to use the CryptoAPI (CAPI) to perform a Diffie Hellman Key Exchange. I'm using the MSDN documentation.

        // Step 0) Acquire context
        if (!CAPI.CryptAcquireContext(ref this._cryptographicProvider, null, null, CAPI.PROV_DSS_DH, CAPI.CRYPT_VERIFYCONTEXT))
            HandleWin32Error("Unable to acquire cryptographic context");

        // Setp 1) Generate private key
        if (!CAPI.CryptGenKey(this._cryptographicProvider, CAPI.CALG_DH_EPHEM, DHKEYSIZE << 16 | CAPI.CRYPT_EXPORTABLE | CAPI.CRYPT_PREGEN, ref this._privateKeyPointer))
            HandleWin32Error("Unable to generate private cryptographic key");

        uint gSize = 0;
        CAPI.CryptGetKeyParam(this._privateKeyPointer, CAPI.KP_G, null, ref gSize, (uint)0);

        byte[] g = new byte[gSize];
        var res = CAPI.CryptGetKeyParam(this._privateKeyPointer, CAPI.KP_G, g, ref gSize, (uint)0);

The first call CryptGetKeyParam works perfectly, i.e. it successfully returns the size of g, as 64.

Then the code fails on the last line, either by returning nothing to the g buffer (as is the case in that example) with res = true, or with an AccessViolationException when I use the following call:

var res = CAPI.CryptGetKeyParam(this._privateKeyPointer, CAPI.KP_G, ref g, ref gSize, (uint)0);

Yes, I've overloaded the P\Invoke methods:

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptGetKeyParam(IntPtr hKey, uint dwParam, ref byte[] pbData, ref uint pdwDataLen, uint dwFlags);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptGetKeyParam(IntPtr hKey, uint dwParam, byte[] pbData, ref uint pdwDataLen, uint dwFlags);

Any thoughts/ideas on this?

*Interestingly, I have managed to get a complete Diffie Hellman Key Exchange to work, i.e. successfully agreeing the same secret (s1) between two parties. But this is with pre-defined P and G parameters. I'm re-working the code because something didn't seem to be correct as the derived secret was the same for every key exchange, implying that X was consistent. (i.e. Bob and Alice agreed on s1 every single time!?) - Here I, again, had an issue with CryptGetKeyParam as I was unable to determine the size of the session key when using KP_KEYLEN?! *

A: 

Ah ha!

It was a combination of the context flags and the overloaded method... Works now!

When P & G are NOT predefined, then don't set the CRYPT_PREGEN flag... And only one of the two overloaded methods was needed (this one):

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptGetKeyParam(IntPtr hKey, uint dwParam, byte[] pbData, ref uint pdwDataLen, uint dwFlags);
cpkblake