C # конвертировать SecureString в UTF-8 байт [] безопасно - PullRequest
0 голосов
/ 29 мая 2018

Я пытаюсь получить SecureString в виде byte[], который я могу держать закрепленным GC, закодированным в формате UTF-8.Я добился успеха в этом, но с UTF-16 (кодировка по умолчанию), но я не могу понять, как выполнить преобразование кодировки без возможности GC создать управляемую копию данных где-то (данные должныбыть в безопасности).

Вот что у меня есть (Контекст: алгоритм для вычисления хэша SecureString)

public static byte[] Hash(this SecureString secureString, HashAlgorithm hashAlgorithm)
{
  IntPtr bstr = Marshal.SecureStringToBSTR(secureString);
  int length = Marshal.ReadInt32(bstr, -4);
  var utf16Bytes = new byte[length];
  GCHandle utf16BytesPin = GCHandle.Alloc(utf16Bytes, GCHandleType.Pinned);
  byte[] utf8Bytes = null;

  try
  {
    Marshal.Copy(bstr, utf16Bytes, 0, length);
    Marshal.ZeroFreeBSTR(bstr);
    // At this point I have the UTF-16 byte[] perfectly.
    // The next line works at converting the encoding, but it does nothing
    // to protect the data from being spread throughout memory.
    utf8Bytes = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, utf16Bytes);
    return hashAlgorithm.ComputeHash(utf8Bytes);
  }
  finally
  {
    if (utf8Bytes != null)
    {
      for (var i = 0; i < utf8Bytes.Length; i++)
      { 
        utf8Bytes[i] = 0;
      }
    }
    for (var i = 0; i < utf16Bytes.Length; i++)
    { 
      utf16Bytes[i] = 0;
    }
    utf16BytesPin.Free();
  }
}

Каков наилучший способ сделать это преобразование, и япытаясь сделать это в правильном месте, как у меня, или я должен сделать это как-то раньше?Может ли это быть более эффективным при использовании памяти, если полностью пропустить шаг UTF-16 byte []?

Ответы [ 2 ]

0 голосов
/ 30 мая 2018

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

[DllImport("kernel32.dll")]
static extern void RtlZeroMemory(IntPtr dst, int length);

public unsafe static byte[] HashNew(this SecureString secureString, HashAlgorithm hashAlgorithm)
{
  IntPtr bstr = Marshal.SecureStringToBSTR(secureString);
  int maxUtf8BytesCount = Encoding.UTF8.GetMaxByteCount(secureString.Length);
  IntPtr utf8Buffer = Marshal.AllocHGlobal(maxUtf8BytesCount);

  // Here's the magic:
  char* utf16CharsPtr = (char*)bstr.ToPointer();
  byte* utf8BytesPtr  = (byte*)utf8Buffer.ToPointer();
  int utf8BytesCount = Encoding.UTF8.GetBytes(utf16CharsPtr, secureString.Length, utf8BytesPtr, maxUtf8BytesCount);

  Marshal.ZeroFreeBSTR(bstr);
  var utf8Bytes = new byte[utf8BytesCount];
  GCHandle utf8BytesPin = GCHandle.Alloc(utf8Bytes, GCHandleType.Pinned);
  Marshal.Copy(utf8Buffer, utf8Bytes, 0, utf8BytesCount);
  RtlZeroMemory(utf8Buffer, utf8BytesCount);
  Marshal.FreeHGlobal(utf8Buffer);
  try
  {
    return hashAlgorithm.ComputeHash(utf8Bytes);
  }
  finally
  {
    for (int i = 0; i < utf8Bytes.Length; i++)
    {
      utf8Bytes[i] = 0;
    }
    utf8BytesPin.Free();
  }
}

Он основан на получении указателей на оба исходных UTF-16строка и буфер UTF-8, затем используется Encoding.UTF8.GetBytes(Char*, Int32, Byte*, Int32) для сохранения преобразования в неуправляемой памяти.

0 голосов
/ 29 мая 2018

Рассматривали ли вы вызов GC.Collect() после получения хэша?

В соответствии с MSDN на GC. Сбор :

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

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

Из того, что я вижу в вашем коде, не должно быть никаких ссылок на объекты, используемые при преобразовании.Все это должно быть собрано и утилизировано ГК.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...