views:

354

answers:

2

I'm trying to P/Invoke into CryptImportKey from C# to set a known key before encrypting data that will be decrypted in a C++ Win32 service at some point. I have the method signature for the P/Invoke and that all works fine but i can't get it to accept my key blob. The C++ structs are in comments below and my C# ones for marshaling are underneath.

        // typedef struct _PUBLICKEYSTRUC 
    // {
    //    BYTE bType;  
    //    BYTE bVersion;  
    //    WORD reserved;  
    //    ALG_ID aiKeyAlg;
    // } BLOBHEADER, PUBLICKEYSTRUC;
    [StructLayout(LayoutKind.Sequential)]
    public struct PUBLICKEYSTRUC
    {
        public Byte bType;
        public Byte bVersion;
        public Int16 reserved;
        public Int32 aiKeyAlg;
    }

    //typedef struct __KEYBLOB 
    //{
    //    BLOBHEADER hdr;
    //    DWORD cbKeySize;
    //    BYTE* rgbKeyData;
    //} KEYBLOB;

    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBLOB
    {
        public PUBLICKEYSTRUC hdr;
        public Int16 cbKeySize;
        public Byte[] rgbKeyData;
    }

I then use:

        int len = (Marshal.SizeOf(typeof(PUBLICKEYSTRUC) + Marshal.SizeOf(typeof(KEYBLOB)) + KeySize;
        byte[] arr = new byte[len];
        IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(keyBlob, ptr, true);
    Marshal.Copy(ptr, arr, 0,len);
        Marshal.FreeHGlobal(ptr);

To get in to a byte array to pass to CryptImportKey but it never seems to take the key with it and when I encrypt with it I get different cipher text time suggesting it's not using my key.

Any ideas would be great!

EDIT:

The key blob stuff is from the C++ code I have that can successfully encrypt and decrypt the data. I think you maybe have a point about the header being included twice but the main problem I have is the value of the Byte[] rgbKeyData is not being put in to the byte array arr.

A: 

Here is a list of structs / imports, which look quite promising. Haven't tested it by myself, though.

Edit:
When you compute the size of your blob: could it be you're actually counting the header twice? Besides, how did you derive the declaration of your KEYBLOB structure?

jn_
Thats where I got the method signature from but it's not help for the structs, I think I'm marshalling wrong. Thanks anyway
L2Type
A: 

On the other hand, why are you even bothering with all this P/Invoke stuff here? The .NET Framework has built-in classes to do all this for you.

Assuming you're using RSA encryption, the RSACryptoServiceProvider class provides an ImportParameters method that accepts a RSAParameters object.
Clean, simple, and the right way to do it.

Is there any reason you can't use this?

AviD
RSACryptoServiceProvider was introduced in .NET 3.5 and we are stuck on .NET 2.0 :(
L2Type
Not at all - Definitely exists in 2.0, pretty sure it was there from from 1.0/1.1 :-). Check again - it should be right there in System.Security.Cryptography. How are you doing the rest of encryption, is it all thru P/Invoke...?
AviD
Yup and all my p/invokes are working apart from this one. I tried RijdaelManaged(sp?) but i couldn't get it to decrypt with the Win32 Crypto API. With all things equal (keys, salts and IVs) trying to decrypt the cipher text failed.
L2Type
Okay, that seems to be a separate question - I suggest you post your code on that, there's no reason it shouldn't work. But you really *should* be using the .NET classes for all your crypto needs - wrapping CryptoAPI is not really such a good idea. And as I said, its all there in 2.0 (even RSA).
AviD