Click here to Skip to main content
15,896,405 members
Articles / Desktop Programming / WPF

Passwords in WPF: How to find yours and how to prevent it being found

Rate me:
Please Sign up or sign in to vote.
4.21/5 (23 votes)
23 Nov 2008CPOL4 min read 77.9K   986   31  
How I can find your password and how to prevent it.
/*
Secure WPF Authentication Sample

History:
29-09-08    1.0 First version

Visit http://blogs.ugidotnet.org/leonardo for updates
*/

using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Security;
using System.Reflection;

namespace SecureWpfLogOn
{
    /// <summary>
    /// Interaction logic for SecureLogOn.xaml
    /// </summary>
    public partial class SecureLogOn : Window
    {
        // Fake char to display in Visual Tree
        private const char PWD_CHAR = '●';

        /// <summary>
        /// Only copy of real password
        /// </summary>
        /// <remarks>For more security use System.Security.SecureString type instead</remarks>
        private StringBuilder pwd = new StringBuilder();

        public SecureLogOn()
        {
            InitializeComponent();            
            InitPwdBox(passwordBox1);            
        }

        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("You have inserted \"" + pwd.ToString() + "\" password");
        }

        private void passwordBox1_PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox pwdBox = (PasswordBox)sender;
            SecurePasswordChanged(pwdBox);
        }

        /// <summary>
        /// PasswordChanged event handler for secure storing of password into Visual Tree
        /// </summary>
        /// <param name="pwdBox">PasswordBox that will be secured</param>
        /// <remarks>Warning: This code require FullTrust and may not work with future release of .Net framework</remarks>
        private void SecurePasswordChanged(PasswordBox pwdBox)
        {
            // If Password is empty clear also this.pwd
            if (pwdBox.Password == "")
            {
                this.pwd = new StringBuilder();
                return;
            }

            // If Password is modified at non last position or any character is deleted then clear it
            // because we can't retrieve what is changed due to PasswordBox control.
            // Only manual insert by one characted at time is allowed
            if (this.pwd.Length != pwdBox.Password.Length - 1)
            {
                pwdBox.Password = "";
                return;
            }
            for (int i = 0; i < pwdBox.Password.Length - 1; i++)
            {
                if (pwdBox.Password[i] != PWD_CHAR)
                {
                    pwdBox.Password = "";
                    return;
                }
            }

            // Append last char from user input to this.pwd field to keep one copy of password
            this.pwd.Append(pwdBox.Password[this.pwd.Length]);            
            
            // To avoid that PasswordChanged event fires again when we clear VisualTree password
            // from PasswordBox (we replace each char with PWD_CHAR), we set directly internal value
            // of password (of type SecureString) with reflection.
            using (SecureString ss2 = StringToSecureString(new string(PWD_CHAR, pwd.Length)))
            {
                _password.SetValue(_textContainer, ss2.Copy());
            }

        }

        /// <summary>
        /// Reference to _textContainer private field of PasswordBox, keept here for performance reason
        /// </summary>
        private Object _textContainer;

        /// <summary>
        /// Referemce to _password private field of _textContainer, keept here for performance reason
        /// </summary>
        private FieldInfo _password;

        /// <summary>
        /// Get references to _password and _textContainer fields of PasswordBox to avoid overheading on each PasswordChanged event call
        /// </summary>        
        private void InitPwdBox(PasswordBox pwdBox)
        {
            _textContainer = pwdBox.GetType().GetField("_textContainer", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(pwdBox);
            _password = _textContainer.GetType().GetField("_password", BindingFlags.NonPublic | BindingFlags.Instance);
        }

        /// <summary>
        /// Convert string into SecureString
        /// </summary>
        /// <param name="str">string to convert</param>
        /// <returns>SecureString copy of str parameter</returns>
        private static SecureString StringToSecureString(string str)
        {
            if (str == null)
            {
                str = string.Empty;
            }
            using (SecureString secStr = new SecureString())
            {
                for (int i = 0; i < str.Length; i++)
                {
                    secStr.AppendChar(str[i]);
                }
                return secStr.Copy();
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Other
Italy Italy
Software Researcher at the University of Parma (Italy)

Comments and Discussions