2013-08-22 32 views
5

Làm cách nào để nhận được số byte[] tương đương với số SecureString (tôi nhận được từ số PasswordBox)?SecureString to Byte [] C#

Mục tiêu của tôi là để viết các byte sử dụng một CryptoStream vào một tập tin, và các phương pháp Write của lớp đó có một đầu vào byte[], vì vậy tôi muốn chuyển đổi SecureString đến byte[] vì vậy tôi có thể sử dụng với một CryptoStream.

EDIT: Tôi không muốn sử dụng string vì nó đánh bại điểm của việc có một SecureString

Trả lời

2

tôi sửa đổi từ original answer để xử lý 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

Không giống như các chuỗi ANSI C, BSTR có thể chứa các ký tự null, do đó việc quét tìm các giá trị rỗng của bạn không hợp lệ. Chỉ cần sử dụng thành viên Length của SecureString nguồn (nhân với 2 để có được số byte). –

-2

mỗi này, http://www.microsoft.com/indonesia/msdn/credmgmt.aspx, bạn có thể sắp xếp nó thành một chuỗi chứng khoán C# và sau đó chuyển đổi đó vào một mảng byte:

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

hoặc mỗi câu trả lời này, How to convert SecureString to System.String?, bạn có thể sử dụng Marshal.ReadByteMarshal.ReadInt16 trên IntPtr để có được những gì bạn cần.

+2

Mặc dù điều đó không đánh bại mục đích của 'SecureString', để cho phép lưu trữ an toàn trong bộ nhớ dữ liệu chuỗi nhạy cảm, chẳng hạn như mật khẩu. – Adrian

+0

Tôi không muốn sử dụng 'chuỗi', vì vậy có cách nào khác, điều đó sẽ vẫn giữ mật khẩu an toàn và hoàn thành cùng một điều không? – inixsoftware

5

Giả sử bạn muốn sử dụng các mảng byte và được thoát khỏi nó càng sớm càng bạn đã hoàn tất, bạn nên đóng gói toàn bộ hoạt động để nó làm sạch lên sau khi chính nó:

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

Và dưới đây là cách một trường hợp sử dụng trông:

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

Không ồn ào, không ồn ào, không có chữ thô nào nổi trong bộ nhớ.

Hãy nhớ rằng mảng byte được chuyển đến func() chứa hiển thị Unicode thô của bản rõ, không phải là vấn đề đối với hầu hết các ứng dụng mã hóa.

+2

Eric - Tôi nghĩ rằng bạn có một vấn đề nhỏ với workArray. thật tuyệt khi bạn đang xóa nó, nhưng điều gì xảy ra nếu người thu gom rác sẽ quyết định di chuyển nó? sau đó bạn có dữ liệu tiếp xúc của bạn là "rác" trong bộ nhớ. bạn cần phải ghim mảng byte vào bộ nhớ trước khi đặt dữ liệu nhạy cảm vào bên trong – ArielB

+1

Bắt tốt, @ArielB. Tôi đã thêm một GCHandle.Alloc() và handle.Free() để ghim xuống workArray cho đến khi nó bị xóa. Muộn còn hơn không. Cảm ơn! –