Phone/Tablet Style password box for WPF application

Is there any way to make the PasswordBox in a WPF application work like the one used in most phone or tablet applications. That is to say, have it show the last character entered in plaintext for a brief period.

Upvotes: 2

Views: 231

Answers (1)

hcham1
hcham1

Reputation: 1847

There is no way built in to do this since it's breaking security guidelines. Please see this post for more information on why this isn't recommended: How to bind to a PasswordBox in MVVM

Here is the accepted answer:

People should have the following security guideline tattooed on the inside of their eyelids: Never keep plain text passwords in memory.

The reason the WPF/Silverlight PasswordBox doesn't expose a DP for the Password property is security related. If WPF/Silverlight were to keep a DP for Password it would require the framework to keep the password itself unencrypted in memory. Which is considered quite a troublesome security attack vector. The PasswordBox uses encrypted memory (of sorts) and the only way to access the password is through the CLR property.

If you still want to achieve this, I was able to do so using a TextBox control.

XAML:

 <TextBox Name="tbPassword"/>

Codebehind:

  string actualPassword = "";
  string displayedPassword = "";
  DispatcherTimer dispatcherTimer = new DispatcherTimer();

  public MainWindow()
  {
     InitializeComponent();
     tbPassword.PreviewKeyDown += tbPassword_PreviewKeyDown;
     tbPassword.PreviewTextInput += tbPassword_PreviewTextInput;

     dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
     dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
  }

  private void tbPassword_PreviewKeyDown(object sender, KeyEventArgs e)
  {
     if (e.Key == Key.Back)
     {
        if (actualPassword.Length > 0)
        {
           actualPassword = actualPassword.Substring(0, actualPassword.Length - 1);
           if (actualPassword.Length > 0)
           {
              ShowLastCharacter();
              tbPassword.CaretIndex = displayedPassword.Length;
           }
        }
     }
  }

  private void tbPassword_PreviewTextInput(object sender, TextCompositionEventArgs e)
  {
     actualPassword += e.Text;
     e.Handled = true;
     ShowLastCharacter();
     tbPassword.CaretIndex = displayedPassword.Length;
  }


  private void ShowLastCharacter()
  {
     var lastChar = actualPassword.Substring(actualPassword.Length - 1);
     displayedPassword = "";
     for (int i = 0; i < actualPassword.Length - 1; i++)
        displayedPassword += "•";
     displayedPassword += lastChar;
     tbPassword.Text = displayedPassword;

     if (dispatcherTimer.IsEnabled)
        dispatcherTimer.Stop();

     dispatcherTimer.Start();
  }

  private void dispatcherTimer_Tick(object sender, EventArgs e)
  {
     displayedPassword = "";
     for (int i = 0; i < actualPassword.Length; i++)
        displayedPassword += "•";

     tbPassword.Text = displayedPassword;
     tbPassword.CaretIndex = displayedPassword.Length;
  }

Upvotes: 2

Related Questions