2013-08-22 13 views
5

Jak uzyskać byte[] odpowiednik (który otrzymuję od PasswordBox)?SecureString do Byte [] C#

Moim celem jest, aby napisać te bajty za pomocą CryptoStream do pliku, a metoda tej klasy Write zajmuje wejście byte[], więc chcę przekonwertować SecureString do byte[] więc mogę korzystać wz CryptoStream.

EDIT: Nie chcę używać string gdyż pokonuje punkt o SecureString

Odpowiedz

2

I zmodyfikowane od original answer do obsługi 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); 
} 
+1

W przeciwieństwie do ciągów ANSI C, BSTRy mogą zawierać znaki puste, więc skanowanie pod kątem zerowych jest nieprawidłowe. Wystarczy użyć elementu Długość źródłowego SecureString (pomnóż przez 2, aby uzyskać liczbę bajtów). –

-2

Per tym http://www.microsoft.com/indonesia/msdn/credmgmt.aspx, można zebrać je w # ciąg Zdjęcie C, a następnie przekonwertować do tablicy bajtów:

static string SecureStringToString(SecureString value) 
{ 
    string s ; 
    IntPtr p = Marshal.SecureStringToBSTR(value); 
    try 
    { 
    s = Marshal.PtrToStringBSTR(p) ; 
    } 
    finally 
    { 
    Marshal.FreeBSTR(p) ; 
    } 
    return s ; 
} 

lub za tą odpowiedź, How to convert SecureString to System.String?, można użyć Marshal.ReadByte i Marshal.ReadInt16 na IntPtr aby uzyskać to, czego potrzebują.

+2

Chociaż to pokonuje cel 'SecureString', który pozwala na bezpieczne przechowywanie poufnych danych ciągów w pamięci, takich jak hasła. – Adrian

+0

Nie chcę używać 'string', więc czy jest jakiś inny sposób, który nadal będzie chronił hasła i osiągnie to samo? – inixsoftware

5

Zakładając, że chcesz korzystać z tablicy bajtów i pozbyć się go tak szybko, jak skończysz, należy upakować całą operację tak, że czyści się po sobie:

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 ***/ 
    } 
} 

A oto jak wygląda przypadek użycia:

private byte[] GetHash(SecureString password) 
{ 
    using (var h = new SHA256Cng()) // or your hash of choice 
    { 
     return password.Process(h.ComputeHash); 
    } 
} 

Żadnych muz, bez zamieszania, żadnego zwykłego tekstu nie pozostającego w pamięci.

Należy pamiętać, że tablica bajtów przekazana do func() zawiera nieprzetworzone wyświetlanie Unicode tekstu jawnego, co nie powinno stanowić problemu w przypadku większości aplikacji kryptograficznych.

+2

Eric - Myślę, że masz niewielki problem z WorkArray. Fajnie, że zerujesz to, ale co, jeśli śmieciarz zdecyduje się go przenieść? wtedy masz zapisane w pamięci dane "śmieci". musisz przypiąć tablicę bajtów do pamięci przed umieszczeniem wrażliwych danych wewnątrz – ArielB

+1

Dobry połów, @ArielB. Dodałem GCHandle.Alloc() i handle.Free(), aby odciążyć obiekt workArray, dopóki nie zostanie wyczyszczony. Lepiej późno niż wcale. Dzięki! –