BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Security
.NET 2.0+

Creating a Secure Textbox

The SecureString class holds confidential information in an encrypted format, reducing the risk that the information could be obtained by reading a computer's memory directly. However, there is no easy way to obtain the secure information from a user.

Processing New Characters

When a new character is entered, it must be inserted into the correct position within the SecureString property. To allow the user to enter text at any point in the string, new characters will always be added at the position held in the textbox's SelectionStart property. Two behaviours are possible. If no text is selected, the new character only requires adding. If the user has selected one or more of the password characters in the textbox, the corresponding characters must be removed from the SecureString before the insertion takes place. We can determine the selection, or lack thereof, by reading SelectionLength.

The code below adds the new behaviour. First we check if any characters are selected. If they are, they are removed from the SecureString property using the RemoveSelectedCharacters method. Next, the new character is inserted at the selection point position. Finally we call the ResetDisplayCharacters method. This sets the Text property of the textbox to a number of password characters that matches the length of the entered string. Note that ResetDisplayCharacters includes a parameter that is used to reset the position of the text cursor, or caret. This is necessary, as setting the Text property changes the caret position. This would give a poor user experience.

private void ProcessNewCharacter(char character)
{
    if (InputBox.SelectionLength > 0)
    {
        RemoveSelectedCharacters();
    }

    _secureString.InsertAt(InputBox.SelectionStart, character);
    ResetDisplayCharacters(InputBox.SelectionStart + 1);
}

private void RemoveSelectedCharacters()
{
    for (int i = 0; i < InputBox.SelectionLength; i++)
    {
        _secureString.RemoveAt(InputBox.SelectionStart);
    }
}

private void ResetDisplayCharacters(int caretPosition)
{
    InputBox.Text = new string(_passwordChar, _secureString.Length);
    InputBox.SelectionStart = caretPosition;
}

Processing Backspaces

When the user presses the backspace key, three behaviours are possible. If the textbox has selected text, this should be removed. If not, the character to the left of the insertion point should be removed and the caret should move accordingly. If the caret is at the far left of the textbox, ie. the SelectionStart value is zero, no action is taken.

private void ProcessBackspace()
{
    if (InputBox.SelectionLength > 0)
    {
        RemoveSelectedCharacters();
        ResetDisplayCharacters(InputBox.SelectionStart);
    }
    else if (InputBox.SelectionStart > 0)
    {
        _secureString.RemoveAt(InputBox.SelectionStart - 1);
        ResetDisplayCharacters(InputBox.SelectionStart - 1);
    }
}

Processing the Delete Key

We now need to process the delete key. When the delete key is pressed, the behaviour is similar to that of the backspace key. If text is selected, it is removed. If not, the character at the selection point is removed, unless the caret is positioned after the last character in the textbox.

We cannot detect the delete key within the Keypress event so will instead use the KeyDown event, as shown below:

private void InputBox_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Delete)
    {
        ProcessDelete();
        e.Handled = true;
    }
}

private void ProcessDelete()
{
    if (InputBox.SelectionLength > 0)
    {
        RemoveSelectedCharacters();
    }
    else if (InputBox.SelectionStart < InputBox.Text.Length)
    {
        _secureString.RemoveAt(InputBox.SelectionStart);
    }

    ResetDisplayCharacters(InputBox.SelectionStart);
}

Finally, there are some keys that will add characters to the textbox, even though they are not generally usable characters. These include the Escape and Enter keys. We can ignore these keys completely with a small modification to the KeyDown event's code.

The code below shows the change. After checking for delete, we test whether the pressed key is one of those that should be ignored, using the IsIgnorableKey method. If such a key is detected, the Handled property is set so that no further action is taken.

private void InputBox_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Delete)
    {
        ProcessDelete();
        e.Handled = true;
    }
    else if (IsIgnorableKey(e.KeyCode))
    {
        e.Handled = true;
    }
}

private bool IsIgnorableKey(Keys key)
{
    return key == Keys.Escape || key == Keys.Enter;
}

Testing the SecureString TextBox

You can now test the new control by adding it to a form. To extract the encrypted value you can use the methods described in the "Creating Secure Strings" article. To see a demonstration, download the Visual Studio solution using the download link at the start of this article.

16 September 2012