Маршаллинг родной функции

1

У меня есть функция в C DLL, которая выполняет вывод ключа SCrypt, но у меня возникла настоящая проблема с сортировкой значений в моей программе на С#.

Объявление функции в 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 и salt передаются в указателях на массивы uint8, N, r и p - значения настройки для алгоритма. Buflen - это размер, который вы хотите, чтобы выходной буфер был. buf является выходным буфером (и, следовательно, либо должен быть ref, либо я думаю);

Я пробовал различные подходы, причем самым последним из них является Marshal.Copy для перемещения данных из IntPtrs в массивы байт (и наоборот), однако, поскольку они являются указателями UInt, а не IntPtr, я не знаю, правильно. В настоящее время он падает, когда я пытаюсь скопировать данные из buf IntPtr и обратно в массив.

Я бы очень признателен за любую помощь.

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();
    }
}
  • 0
    Я бы, вероятно, использовал следующее объявление: public static extern int scrypt(byte[] passwd, uint passwdlen, byte[] salt, uint saltlen, ulong N, uint r, uint p, byte[] buf, uint buflen) . А на стороне .NET нормализуйте свой пароль и сначала преобразуйте его в UTF-8. Вы получите байт [], который вы можете использовать напрямую.
  • 0
    Это работает. Как только я добавил Out или ref в buf, он снова рухнул ... что я совсем не ожидал. Если вы хотите опубликовать это как ответ, я буду рад отметить это как правильное.
Показать ещё 1 комментарий
Теги:
pinvoke
marshalling

1 ответ

1
Лучший ответ

Я бы, вероятно, использовал следующее объявление функции:

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

Имейте в виду, что существует несколько различных способов сортировки определенных типов, но в этом случае приведенный выше вариант, вероятно, является самым ясным, поскольку он сопоставляется непосредственно с соответствующими типами.

Вы можете тривиально преобразовать string в byte[], запросив Encoding для этого. В случае паролей, пока вы конвертируете в Юникод, все должно быть хорошо. Но обязательно используйте один и тот же вариант в любом месте, где может потребоваться преобразовать пароль в byte[].

Ещё вопросы

Сообщество Overcoder
Наверх
Меню