SecureString a Byte[] C#
wpf encryption (3)
Modifiqué de la respuesta original para manejar 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);
}
¿Cómo obtendría un byte[]
equivalente a un SecureString
(que obtengo de un PasswordBox
)?
Mi objetivo es escribir estos bytes usando un CryptoStream
en un archivo, y el método Write
de esa clase toma una entrada byte[]
, por lo que quiero convertir SecureString
en el byte[]
para que pueda usarlo con CryptoStream
.
EDITAR: no quiero usar string
ya que se SecureString
el punto de tener un SecureString
Según esto, http://www.microsoft.com/indonesia/msdn/credmgmt.aspx , puede convertirlo en una cadena C # estándar y luego convertirlo en una matriz de bytes:
static string SecureStringToString( SecureString value )
{
string s ;
IntPtr p = Marshal.SecureStringToBSTR( value );
try
{
s = Marshal.PtrToStringBSTR( p ) ;
}
finally
{
Marshal.FreeBSTR( p ) ;
}
return s ;
}
o según esta respuesta, ¿Cómo convertir SecureString a System.String? , puede usar Marshal.ReadByte
y Marshal.ReadInt16
en IntPtr
para obtener lo que necesita.
Suponiendo que desea utilizar la matriz de bytes y deshacerse de ella tan pronto como haya terminado, debe encapsular toda la operación para que se limpie después de sí misma:
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 ***/
}
}
Y así es como se ve un caso de uso:
private byte[] GetHash(SecureString password)
{
using (var h = new SHA256Cng()) // or your hash of choice
{
return password.Process(h.ComputeHash);
}
}
Sin rumores, sin problemas, sin texto claro dejado flotando en la memoria.
Tenga en cuenta que la matriz de bytes que se pasa a func()
contiene la representación en bruto Unicode del texto plano, lo que no debería ser un problema para la mayoría de las aplicaciones criptográficas.