亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

C# 將 SecureString 安全地轉換為 UTF-8 byte[]

C# 將 SecureString 安全地轉換為 UTF-8 byte[]

C#
狐的傳說 2021-07-07 17:57:12
我正在嘗試進入 aSecureString的形式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 回答

?
波斯汪

TA貢獻1811條經驗 獲得超4個贊

我找到了一種方法來按照我想要的方式做到這一點。我這里的代碼還沒有完成(在失敗的情況下需要更好的異常處理和內存管理),但這里是:


[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)用于將轉換保留在非托管內存中。


查看完整回答
反對 回復 2021-07-10
?
ibeautiful

TA貢獻1993條經驗 獲得超6個贊

有沒有考慮GC.Collect()在獲得hash后調用?

根據GC.Collect上的MSDN

強制立即對所有代進行垃圾收集。使用此方法嘗試回收所有無法訪問的內存。它執行所有代的阻塞垃圾收集。

所有對象,無論它們在內存中的時間有多長,都被考慮收集;但是,不會收集托管代碼中引用的對象。使用此方法強制系統嘗試回收最大量的可用內存。

從我在您的代碼中看到的,它不應該保留對轉換中使用的對象的任何引用。這一切都應該由 GC 收集和處理。


查看完整回答
反對 回復 2021-07-10
  • 2 回答
  • 0 關注
  • 289 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號