elaverick
elaverick

Reputation: 312

Marshalling native function

I have a function in a C DLL that performs SCrypt key derivation, but I'm having real trouble marshalling the values into my C# program.

The function declaration is as follows in C:

__declspec(dllexport) int scrypt(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,uint8_t * buf, size_t buflen);

passwd and salt are both passed in a pointers to uint8 arrays, N, r and p are tuning values for the algorithm. Buflen is the size you wish the output buffer to be. buf is the output buffer (and so either needs to be a ref or an out I think);

I've tried various approaches, with the most recent being Marshal.Copy to move data out of the IntPtrs into byte arrays (and vice-versa), however as these are UInt pointers as opposed to IntPtr I don't know if that is right. Currently it crashes when I try and copy the data out of the buf IntPtr and back into the array.

I'd really appreciate any assistance.

class Program
{
    [DllImport("SCrypt.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
    public static extern int scrypt(IntPtr passwd, UIntPtr passwdlen, IntPtr salt, UIntPtr saltlen, UInt64 N, UInt32 r, UInt32 p, out IntPtr buf, UIntPtr buflen);

    static void Main(string[] args)
    {
        byte[] encoded = new byte[32];
        IntPtr encodedptr;

        byte[] password = System.Text.Encoding.Unicode.GetBytes("test");
        byte[] salt = System.Text.Encoding.Unicode.GetBytes("ThisistheSaltweareusingforthiskey");
        IntPtr passwordptr, saltptr;

        passwordptr = Marshal.AllocHGlobal(password.Length);
        Marshal.Copy(password, 0, passwordptr, password.Length);

        saltptr = Marshal.AllocHGlobal(salt.Length);
        Marshal.Copy(salt, 0, saltptr, salt.Length);

        int returnVal = scrypt(passwordptr, (UIntPtr)password.Length, saltptr, (UIntPtr)salt.Length, 262144, 8, 1,out encodedptr,(UIntPtr) 32);

        Marshal.Copy(encodedptr, encoded, 0, 32);

        Console.WriteLine(BitConverter.ToString(encoded));
        Console.ReadKey();
    }
}

Upvotes: 1

Views: 403

Answers (1)

Joey
Joey

Reputation: 354406

I'd probably use the following function declaration:

public static extern int scrypt(byte[] passwd, uint passwdlen, byte[] salt, uint saltlen, ulong N, uint r, uint p, byte[] buf, uint buflen).

Keep in mind that there are multiple different ways of marshalling certain types, but in this case the above variant is probably the clearest because it maps directly to the respective types.

You can trivially convert a string to a byte[] by asking an Encoding to do so for you. In the case of passwords as long as you convert to Unicode everything should be fine. But make sure to use the same variant in every place that might need to convert a password to a byte[].

Upvotes: 1

Related Questions