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);
                    }
                }
            }
        }