У меня есть функция в 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();
}
}
Я бы, вероятно, использовал следующее объявление функции:
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[]
.
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. Вы получите байт [], который вы можете использовать напрямую.