Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

PasswordBox: A Better Way to Enter Passwords

0.00/5 (No votes)
17 Mar 2003 1  
A better way to enter passwords.

Screenshot

Introduction

Have you ever taken a good look at that TextBox control you are using to let users enter a password? Have you wondered why you can't get the TextBox to show the black dots instead of * as a password is entered?

This article presents the PasswordBox control and attempts to address the issues surrounding the use of a TextBox control for input of a password or other secure data.

Background

I was happily coding away on the options dialog for my latest project and was ready to test the dialog. When I ran my app and opened the dialog I noticed something wasn't right. All the controls had the XP visual styles (I was using a manifest). That is, they all had the visual styles except one...The password field! It displayed *'s instead of the black dots one has come to expect.

I searched high and low, on MSDN and the rest of the internet (yes, including The Code Project)...I found nothing to help.

I asked in a Microsoft newsgroup...The only answer I got involved assigning UNICODE character 25CF to PasswordChar.

// Give me the black dots!

textBox1.PasswordChar = (char)0x25CF;        

I wasn't happy with this solution [read "hack"] since it wouldn't work on all systems. So I started doing more research. What I found surprised me.

I started up Outlook Express (OE) and fired up SPY++ to have a look at the password field in the account properties dialog. When I compared the password field in OE with the TextBox control I found that OE uses the ES_PASSWORD style flag. Now, one may think that by assigning "*" to the PasswordChar member the TextBox control would then use this this style also...Nope! (OK, I should have remembered ES_PASSWORD from coding dialogs in VC++)

While inspecting the .NET TextBox with SPY++ I could see the password that was entered! Could it be there is this security hole? I checked, I COULD NOT see the password entered into OE.

How easy would it be for a malicious hacker to write a something to read your passwords from a password field? Dead easy!

As I see it now there are at least 2 major issues surrounding the use of the TextBox control for input of a password. I will now address both of these issues individually, in no particular order of importance.

Where are the black dots?

As it turns out, this was the simplest issue to resolve.

I originally set out to use P/Invoke to call GetWindowsLong & SetWindowsLong to try to modify the style of the TextBox and add the ES_PASSWORD style flag. While searching for the documentation on this I came across the CreateParams member of the Form class.

I won't go into great detail on this member since you can look it up yourself in the online help. Suffice it to say, for those familiar with MFC development, I liken CreateParams to the PreCreateWindow function.

Getting the black dots to show up based on the visual style was insanely simple!

// Class definition for PasswordBox

public class PasswordBox : TextBox
{

    private const int ES_PASSWORD = 0x0020;
    ...

    protected override CreateParams CreateParams
    {
        CreateParams cp = base.CreateParams;
        ...

        cp.Style |= ES_PASSWORD;
        ...
        
        return cp;
    }
}        

This solved the issue of the black dots. And should work on any system supporting the .NET Framework. If it doesn't, I'm sure one of you will let me know. Just don't be too rough on me :)

And what about security?

It was at this point I thought I had my solution. I couldn't have been more wrong...WRONG!.

I discovered that using the ES_PASSWORD style only created what I needed visually. I could still see the password using SPY++. This was going to take a little more work.

To hide a password from prying eyes I found that I needed to define a private internal buffer.

    ...
    private System.Text.StringBuilder _internalBuffer 
        = new System.Text.StringBuilder();
    ...

In order to get the keyboard input into my buffer I had to capture keystrokes.

At first I used KeyDown and KeyPress event handlers. The code for editing the internal buffer while feeding '\0x20' to the base TextBox class was cumbersome and fairly effective, but, it had some problems.

The most noticeable problem was pasting text from the clipboard. The keyboard events just didn't provide the means to capture the keystrokes and handle them myself. So, I resigned myself to the fact that I was going to have to override WndProc and do all this by hand.

While researching how to do this in C# I stumbled across 2 methods:

    protected virtual bool ProcessCmdKey(ref Message msg, Keys keyData);
    protected internal virtual bool ProcessKeyMessage(ref Message m);

Again, I won't go into any detail on the usage of these methods, since you can read all about them in your online help or on MSDN. I overrode these 2 methods and all my problems were solved!

ProcessCmdKey allowed me to capture Ctrl+V and the Delete key to handle a paste and delete operations the way I needed. And ProcessKeyMessage let me to process each the WM_CHAR message so that I could grab the character being input put it into my buffer and send '\0x20' back through the message loop

Using the Code

Using the code couldn't be simpler. Your first option is to build the control project then add the component to you tool bar. Once on your toolbar simply drag and drop the control onto your form. From there just treat it like any TextBox control.

The next option is to add build the control project and add it to your references of your own project. In your Form code add a declaration for PasswordBox. And again, treat it like any other TextBox control.

    public class MyLogin : Form
    {
        ...
        private PasswordBox _password;
        ...

        public MyLogin()
        {
            _password = new PasswordBox();
            ...
        }
        ...
    }

You last option is less scalable, but you could simply copy the PasswordBox.cs file to your own project and use it as in the previous option.

Note: You can still assign a value to PasswordChar, such as '*', but be aware, you will get that character instead of the black dots, regardless of the visual style in use.

Points of Interest

I found a couple of interesting [read strange] things. Take a look at a TextBox with SPY++, you will see that the WS_MAXIMIZEBOX  style is added to the control. What's that all about? I haven't figured that out. In the source I have included the code you need to remove the style if you choose. I haven't noticed any adverse affects when it is removed, but chose to leave it alone. You are welcome to try on your own.

The other thing I found was an issue with the ES_PASSWORD style. I wrote and experimented with this code for a few days. Each time I ran the code I would check the style flags with SPY++ and each time I would see the ES_PASSWORD style flag. Then at some point I had to restart VS.NET for some reason. From then on, every time I inspected my PasswordBox, I have not seen the ES_PASSWORD style flag. Although the PasswordBox does still behave as if the style flag were set. Maybe you will have different results.

Room for Improvement

As with anything, there is always room for improvement. In the case of PasswordBox there is one thing that comes to mind, the balloon help that pops up when you try to copy the text from a password field.

When using using a TextBox with PasswordChar='*' and you try to copy the text, you get a balloon help that says, "Not Allowed", "You cannot copy text from a password field". With PasswordBox there is no balloon help.

History

03/16/2003 - Initial release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here