private static byte[] ComputeHash(HashAlgorithm algorithm, byte[] prefixBytes, SecureString secureString) { #if NETCORE50 || NETSTANDARD1_5 || NETSTANDARD1_6 var bstr = MarshalExtentsions.SecureStringToBSTR(secureString); #else var bstr = Marshal.SecureStringToBSTR(secureString); #endif try { var passwordChars = new char[secureString.Length]; var passwordCharsHandle = GCHandle.Alloc(passwordChars, GCHandleType.Pinned); try { Marshal.Copy(bstr, passwordChars, 0, passwordChars.Length); var passwordBytes = new byte[secureString.Length * 3]; // worst case for UTF16 to UTF8 encoding var passwordBytesHandle = GCHandle.Alloc(passwordBytes, GCHandleType.Pinned); try { var encoding = Utf8Encodings.Strict; var passwordUtf8Length = encoding.GetBytes(passwordChars, 0, passwordChars.Length, passwordBytes, 0); var buffer = new byte[prefixBytes.Length + passwordUtf8Length]; Buffer.BlockCopy(prefixBytes, 0, buffer, 0, prefixBytes.Length); Buffer.BlockCopy(passwordBytes, 0, buffer, prefixBytes.Length, passwordUtf8Length); var hash = algorithm.ComputeHash(buffer); Array.Clear(buffer, 0, buffer.Length); return(hash); } finally { Array.Clear(passwordBytes, 0, passwordBytes.Length); passwordBytesHandle.Free(); } } finally { Array.Clear(passwordChars, 0, passwordChars.Length); passwordCharsHandle.Free(); } } finally { Marshal.ZeroFreeBSTR(bstr); } }
public static string MongoPasswordDigest(string username, SecureString password) { using (var md5 = MD5.Create()) { var bytes = Utf8Encodings.Strict.GetBytes(username + ":mongo:"); IntPtr unmanagedPassword = IntPtr.Zero; try { #if NETCORE50 || NETSTANDARD1_5 || NETSTANDARD1_6 unmanagedPassword = MarshalExtentsions.SecureStringToBSTR(password); #else unmanagedPassword = Marshal.SecureStringToBSTR(password); #endif var passwordChars = new char[password.Length]; GCHandle passwordCharsHandle = new GCHandle(); try { passwordCharsHandle = GCHandle.Alloc(passwordChars, GCHandleType.Pinned); Marshal.Copy(unmanagedPassword, passwordChars, 0, passwordChars.Length); var byteCount = Utf8Encodings.Strict.GetByteCount(passwordChars); var passwordBytes = new byte[byteCount]; GCHandle passwordBytesHandle = new GCHandle(); try { passwordBytesHandle = GCHandle.Alloc(passwordBytesHandle, GCHandleType.Pinned); Utf8Encodings.Strict.GetBytes(passwordChars, 0, passwordChars.Length, passwordBytes, 0); var buffer = new byte[bytes.Length + passwordBytes.Length]; Buffer.BlockCopy(bytes, 0, buffer, 0, bytes.Length); Buffer.BlockCopy(passwordBytes, 0, buffer, bytes.Length, passwordBytes.Length); return(BsonUtils.ToHexString(md5.ComputeHash(buffer))); } finally { Array.Clear(passwordBytes, 0, passwordBytes.Length); if (passwordBytesHandle.IsAllocated) { passwordBytesHandle.Free(); } } } finally { Array.Clear(passwordChars, 0, passwordChars.Length); if (passwordCharsHandle.IsAllocated) { passwordCharsHandle.Free(); } } } finally { if (unmanagedPassword != IntPtr.Zero) { Marshal.ZeroFreeBSTR(unmanagedPassword); } } } }