我該如何得到一個byte[]
的等價物SecureString
(我從PasswordBox
得到)?SecureString to Byte [] C#
我的目標是使用CryptoStream
到一個文件中寫入這些字節,而類Write
方法採用byte[]
輸入,所以我要轉換的SecureString
到byte[]
這樣我就可以使用與CryptoStream
。
編輯:我不想用string
,因爲它違背了一個SecureString
我該如何得到一個byte[]
的等價物SecureString
(我從PasswordBox
得到)?SecureString to Byte [] C#
我的目標是使用CryptoStream
到一個文件中寫入這些字節,而類Write
方法採用byte[]
輸入,所以我要轉換的SecureString
到byte[]
這樣我就可以使用與CryptoStream
。
編輯:我不想用string
,因爲它違背了一個SecureString
我從original answer修改,以處理Unicode的
IntPtr unmanagedBytes = Marshal.SecureStringToGlobalAllocUnicode(password);
byte[] bValue = null;
try
{
byte* byteArray = (byte*)unmanagedBytes.GetPointer();
// Find the end of the string
byte* pEnd = byteArray;
char c='\0';
do
{
byte b1=*pEnd++;
byte b2=*pEnd++;
c = '\0';
c= (char)(b1 << 8);
c += (char)b2;
}while (c != '\0');
// Length is effectively the difference here (note we're 2 past end)
int length = (int)((pEnd - byteArray) - 2);
bValue = new byte[length];
for (int i=0;i<length;++i)
{
// Work with data in byte array as necessary, via pointers, here
bValue[i] = *(byteArray + i);
}
}
finally
{
// This will completely remove the data from memory
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedBytes);
}
每本點,http://www.microsoft.com/indonesia/msdn/credmgmt.aspx,你可以封成一個股票C#字符串,然後再轉換到一個數組字節:
static string SecureStringToString(SecureString value)
{
string s ;
IntPtr p = Marshal.SecureStringToBSTR(value);
try
{
s = Marshal.PtrToStringBSTR(p) ;
}
finally
{
Marshal.FreeBSTR(p) ;
}
return s ;
}
或每股這個答案,How to convert SecureString to System.String?,您可以使用Marshal.ReadByte
和Marshal.ReadInt16
的IntPtr
得到你所需要的。
儘管這確實違背了「SecureString」的目的,即允許安全地在內存中存儲敏感字符串數據(如密碼)。 – Adrian
我不想使用'string',那麼有沒有其他的方法,這將仍然保持密碼安全並完成相同的事情? – inixsoftware
假設你要使用的字節數組,一旦大功告成擺脫它,你應該封裝整個操作,這樣可以清理達後本身:
public static T Process<T>(this SecureString src, Func<byte[], T> func)
{
IntPtr bstr = IntPtr.Zero;
byte[] workArray = null;
GCHandle handle = GCHandle.Alloc(workArray, GCHandleType.Pinned);
try
{
/*** PLAINTEXT EXPOSURE BEGINS HERE ***/
bstr = Marshal.SecureStringToBSTR(src);
unsafe
{
byte* bstrBytes = (byte*)bstr;
workArray = new byte[src.Length * 2];
for (int i = 0; i < workArray.Length; i++)
workArray[i] = *bstrBytes++;
}
return func(workArray);
}
finally
{
if (workArray != null)
for (int i = 0; i < workArray.Length; i++)
workArray[i] = 0;
handle.Free();
if (bstr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstr);
/*** PLAINTEXT EXPOSURE ENDS HERE ***/
}
}
而這裏的用例的外觀:
private byte[] GetHash(SecureString password)
{
using (var h = new SHA256Cng()) // or your hash of choice
{
return password.Process(h.ComputeHash);
}
}
沒有麻煩,沒有大驚小怪,沒有明文留在記憶中。
請記住,傳遞給func()
的字節數組包含明文的原始Unicode渲染,這對大多數加密應用程序來說不應該是個問題。
埃裏克 - 我認爲你的工作陣列有一個小問題。 很好,你正在調零它,但如果垃圾收集器將決定移動它呢?那麼你的暴露數據就是內存中的「垃圾」。 在將敏感數據放入 – ArielB
之前,您需要將字節數組固定到內存中。好的,@ArielB。我已經添加了一個GCHandle.Alloc()和handle.Free()來關閉workArray直到它被清除。遲到總比不到好。謝謝! –
與ANSI C字符串不同,BSTR可以包含空字符,因此您的空值掃描無效。只需使用源SecureString的Length成員(乘以2得到字節數)。 –