using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace Common.Utils { /// /// An extension class to handle SecureString conversion /// internal static class SecureStringExtensions { public static readonly Encoding ENCODING = Encoding.UTF8; #region methods /// /// Convert the content of the SecureString as an array of bytes /// /// /// A Byte Array representation of a secure string public static byte[] ConvertToByteArray(this SecureString password) { if (password == null) { throw new SecureStringConversionException("Cannot convert a null password"); } IntPtr stringTempPass = IntPtr.Zero; string convertedPass; try { stringTempPass = Marshal.SecureStringToGlobalAllocUnicode(password); convertedPass = Marshal.PtrToStringUni(stringTempPass); if (convertedPass != null) return ENCODING.GetBytes(convertedPass); else return null; } finally { Marshal.ZeroFreeGlobalAllocUnicode(stringTempPass); } } /// /// Convert the content of a byte array to a secure string /// /// /// The representation of the byte array in a secure string public static SecureString ConvertByteArrayToSecureString(this byte[] arrayToConvert) { IntPtr stringPointer = IntPtr.Zero; if (arrayToConvert.Length == 0) throw new ArgumentException("Password is empty"); stringPointer = Marshal.StringToBSTR(ENCODING.GetString(arrayToConvert)); try { return ConvertToSecureString(Marshal.PtrToStringBSTR(stringPointer)); } finally { Marshal.ZeroFreeBSTR(stringPointer); GC.Collect(); } } /// /// Convert a secure string to a char array /// /// /// A representation of the secure string in a char array public static char[] ConvertToCharArray(this SecureString password) { char[] charArray = new char[password.Length]; IntPtr charPass = IntPtr.Zero; try { charPass = Marshal.SecureStringToCoTaskMemUnicode(password); Marshal.Copy(charPass, charArray, 0, password.Length); return charArray; } finally { if (charPass != IntPtr.Zero) { Marshal.ZeroFreeGlobalAllocUnicode(charPass); } } } /// /// Convert a SecureString to string. Used for compliancy with MSFT WINRM DLL /// /// /// a string represetation of a secure string public static string ConvertToString(this SecureString password) { IntPtr stringPointer = IntPtr.Zero; if (password == null) throw new ArgumentNullException("Password is empty"); stringPointer = Marshal.SecureStringToBSTR(password); try { return Marshal.PtrToStringBSTR(stringPointer); } finally { Marshal.ZeroFreeBSTR(stringPointer); } } /// /// Convert a String object to SecureString /// /// /// A secure string representation of a string object public static SecureString ConvertToSecureString(this string password) { var securePass = new SecureString(); foreach (var c in password) securePass.AppendChar(c); securePass.MakeReadOnly(); return securePass; } /// /// Compare the value of secure string object /// /// /// /// true/false according to the values equality public static bool ValueEquals(this SecureString password, SecureString value) { IntPtr passBstr = IntPtr.Zero; IntPtr valueBstr = IntPtr.Zero; try { passBstr = Marshal.SecureStringToBSTR(password); valueBstr = Marshal.SecureStringToBSTR(value); int passLength = Marshal.ReadInt32(passBstr, -4); int valueLength = Marshal.ReadInt32(valueBstr, -4); if (passLength != valueLength) return false; for (int x = 0; x < passLength; ++x) { byte passByte = Marshal.ReadByte(passBstr, x); byte valueByte = Marshal.ReadByte(valueBstr, x); if (passByte != valueByte) return false; } return true; } finally { if (passBstr != IntPtr.Zero) Marshal.ZeroFreeBSTR(passBstr); if (valueBstr != IntPtr.Zero) Marshal.ZeroFreeBSTR(valueBstr); } } } public class SecureStringConversionException : Exception { public SecureStringConversionException() { } public SecureStringConversionException(string message) : base(message) { } public SecureStringConversionException(string message, Exception innerException) : base(message, innerException) { } } } #endregion