I know this was asked ages ago, but I thoght I'd give my solution in case someone stumbles upon it as I did.
I achieved this by using WindowsForms and trapping the KeyPress events for a regular text box (instead of a password box). Instead of allowing the event to populate the text box, I generate a '*' character and insert the character directly into a SecureString. This way the password is never in memory... for the most part..
KeyDown is fired first:
private void Password_KeyDown(object sender, KeyEventArgs e)
{
TextBox caller = sender as TextBox;
int position = caller.SelectionStart;
_PasswordBoxControlDown = e.Control; // toggle if control is also down
switch (e.KeyCode)
{
case Keys.Delete: //delete pressed
if (caller.SelectionLength > 0) //more than 1 character selected
{
for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
_SecurePassword.RemoveAt(caller.SelectionStart); //remove from secure password
caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength); //update textbox to reflect number of characters
KeyDownDidSomething(caller, e, position);
}
else if (caller.SelectionStart < caller.Text.Length) // nothing selected - but cursor is not at the end of textbox
{
_SecurePassword.RemoveAt(caller.SelectionStart);
caller.Text = caller.Text.Remove(caller.SelectionStart, 1);
KeyDownDidSomething(caller, e, position);
}
break;
case Keys.Back: //backspace pressed
if (caller.SelectionLength > 0) //more than 1 character selected
{
for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
_SecurePassword.RemoveAt(caller.SelectionStart); //remove from secure password
caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength); //update textbox to reflect number of characters
KeyDownDidSomething(caller, e, position);
}
else if (caller.SelectionStart > 0) // nothing selected - but cursor is not at the beginning of textbox
{
_SecurePassword.RemoveAt(caller.SelectionStart - 1);
caller.Text = caller.Text.Remove(caller.SelectionStart - 1, 1);
position--;
KeyDownDidSomething(caller, e, position);
}
break;
}
}
e.Handled = true; //tells the text box that the event has been handled, text box will not write character to text box.
caller.SelectionLength = 0;
}
private void KeyDownDidSomething(TextBox caller, KeyEventArgs e, int position)
{
//use this to do whatever you need to do when you handle an event (if at all)
}
Followed by KeyPress
private const char ENTER_KEY = (char)13;
private const char CNTRL_V = (char)22;
private void Password_KeyPress(object sender, KeyPressEventArgs e)
{
TextBox caller = sender as TextBox;
char ch = e.KeyChar;
int position = caller.SelectionStart;
if (ch >= 32 && ch <= 126) //acceptable password symbol
{
int len = caller.SelectionLength;
if (caller.SelectionLength > 0) //Handles inserting when text is selected (removing selected characters)
{
for (int i = caller.SelectionStart; i < caller.SelectionStart + caller.SelectionLength; i++)
_SecurePassword.RemoveAt(caller.SelectionStart);
caller.Text = caller.Text.Remove(caller.SelectionStart, caller.SelectionLength);
}
_SecurePassword.InsertAt(position, ch);
caller.Text = caller.Text + '*'; //generate a * so the user knows how many characters they've entered
caller.SelectionStart = position + 1;
}
else //handle other symbol
{
switch (ch)
{
case CNTRL_V:
Password_PasteClicked(null, null); //handle paste event
break;
case ENTER_KEY:
SaveAndCloseButton_Click(null, null); //handle enter .. if you want to.
break;
//add events for any special characters here
}
}
Kind of gives the illusion that it's maintaining the password in the password box. Anyways, throw a _SecurePassword.Dispose() when you're done with the password.