SecurePasswordTextBox 阻止制表符和输入键工作
SecurePasswordTextBox preventing tab and enter keys working
我已经使用 SecurePasswordTextBox 的修改版本在我的 WinForms 应用程序上创建安全输入控件(是的,我知道这在很大程度上毫无意义,但我们的一位客户一直坚持不应该将敏感数据处理为内存中的字符串。
但是,出于某种原因。在选择控件后,这似乎破坏了窗体的 tab
和 enter
键。我们不能再使用它们在控件之间跳转。我将如何解决这个问题?我试过使用 SendKeys()
但这似乎没有帮助。
来源如下。我通过添加覆盖 Clear()
函数对其进行了修改。
namespace SecurePasswordTextBox
{
/// <summary>
/// This is a TextBox implementation that uses the System.Security.SecureString as its backing
/// store instead of standard managed string instance. At no time, is a managed string instance
/// used to hold a component of the textual entry.
/// It does not display any text and relies on the 'PasswordChar' character to display the amount of
/// characters entered. If no password char is defined, then an 'asterisk' is used.
/// </summary>
public partial class SecureTextBox : TextBox
{
#region Private fields
private bool _displayChar = false;
SecureString _secureEntry = new SecureString();
private TextBox _innerTextBox = new TextBox();
#endregion
#region Constructor
public SecureTextBox()
{
InitializeComponent();
this.PasswordChar = '*'; // default to an asterisk
}
#endregion
#region Public properties
/// <summary>
/// The secure string instance captured so far.
/// This is the preferred method of accessing the string contents.
/// </summary>
public SecureString SecureText
{
get
{
return _secureEntry;
}
set
{
_secureEntry = value;
}
}
/// <summary>
/// Allows the consumer to retrieve this string instance as a character array. NOte that this is still
/// visible plainly in memory and should be 'consumed' as wuickly as possible, then the contents
/// 'zero-ed' so that they cannot be viewed.
/// </summary>
public char[] CharacterData
{
get
{
char[] bytes = new char[_secureEntry.Length];
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.SecureStringToBSTR(_secureEntry);
bytes = new char[_secureEntry.Length];
Marshal.Copy(ptr, bytes,0,_secureEntry.Length);
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(ptr);
}
return bytes;
}
}
#endregion
#region ProcessKeyMessage
protected override bool ProcessKeyMessage(ref Message m)
{
if (_displayChar)
{
return base.ProcessKeyMessage(ref m);
}
else
{
_displayChar = true;
return true;
}
}
#endregion
#region IsInputChar
protected override bool IsInputChar(char charCode)
{
int startPos = this.SelectionStart;
bool isChar = base.IsInputChar(charCode);
if (isChar)
{
int keyCode = (int)charCode;
// If the key pressed is NOT a control/cursor type key, then add it to our instance.
// Note: This does not catch the SHIFT key or anything like that
if (!Char.IsControl(charCode) && !char.IsHighSurrogate(charCode) && !char.IsLowSurrogate(charCode))
{
if (this.SelectionLength > 0)
{
for (int i = 0; i < this.SelectionLength; i++)
_secureEntry.RemoveAt(this.SelectionStart);
}
if (startPos == _secureEntry.Length)
{
_secureEntry.AppendChar(charCode);
}
else
{
_secureEntry.InsertAt(startPos, charCode);
}
this.Text = new string('*', _secureEntry.Length);
_displayChar = false;
startPos++;
this.SelectionStart = startPos;
}
else
{
// We need to check what key has been pressed.
switch (keyCode)
{
case (int)Keys.Back:
if (this.SelectionLength == 0 && startPos > 0)
{
startPos--;
_secureEntry.RemoveAt(startPos);
this.Text = new string('*', _secureEntry.Length);
this.SelectionStart = startPos;
}
else if (this.SelectionLength > 0)
{
for (int i = 0; i < this.SelectionLength; i++)
_secureEntry.RemoveAt(this.SelectionStart);
}
_displayChar = false; // If we dont do this, we get a 'double' BACK keystroke effect
break;
}
}
}
else
_displayChar = true;
return isChar;
}
#endregion
#region IsInputKey
protected override bool IsInputKey(Keys keyData)
{
bool result = true;
// Note: This whole section is only to deal with the 'Delete' key.
bool allowedToDelete =
(
((keyData & Keys.Delete) == Keys.Delete)
);
// Debugging only
//this.Parent.Text = keyData.ToString() + " " + ((int)keyData).ToString() + " allowedToDelete = " + allowedToDelete.ToString();
if (allowedToDelete)
{
if (this.SelectionLength == _secureEntry.Length)
{
_secureEntry.Clear();
}
else if (this.SelectionLength > 0)
{
for (int i = 0; i < this.SelectionLength; i++)
_secureEntry.RemoveAt(this.SelectionStart);
}
else
{
if ((keyData & Keys.Delete) == Keys.Delete && this.SelectionStart < this.Text.Length)
_secureEntry.RemoveAt(this.SelectionStart);
}
}
return result;
}
#endregion
}
}
我可以通过添加以下内容来检测何时按下 Tab
:
case (int)Keys.Tab:
到switch(KeyCode)
块。但是,我不知道如何手动调用它通常具有的 "Select Next Control By Tab Index" 效果。
在这种情况下添加 SelectNextControl((Control)this, true, true, true, true);
似乎也不起作用。
在您的 IsInputKey 覆盖中,只需检查 Tab 键:
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Tab) {
return false;
}
// your code ...
}
我已经使用 SecurePasswordTextBox 的修改版本在我的 WinForms 应用程序上创建安全输入控件(是的,我知道这在很大程度上毫无意义,但我们的一位客户一直坚持不应该将敏感数据处理为内存中的字符串。
但是,出于某种原因。在选择控件后,这似乎破坏了窗体的 tab
和 enter
键。我们不能再使用它们在控件之间跳转。我将如何解决这个问题?我试过使用 SendKeys()
但这似乎没有帮助。
来源如下。我通过添加覆盖 Clear()
函数对其进行了修改。
namespace SecurePasswordTextBox
{
/// <summary>
/// This is a TextBox implementation that uses the System.Security.SecureString as its backing
/// store instead of standard managed string instance. At no time, is a managed string instance
/// used to hold a component of the textual entry.
/// It does not display any text and relies on the 'PasswordChar' character to display the amount of
/// characters entered. If no password char is defined, then an 'asterisk' is used.
/// </summary>
public partial class SecureTextBox : TextBox
{
#region Private fields
private bool _displayChar = false;
SecureString _secureEntry = new SecureString();
private TextBox _innerTextBox = new TextBox();
#endregion
#region Constructor
public SecureTextBox()
{
InitializeComponent();
this.PasswordChar = '*'; // default to an asterisk
}
#endregion
#region Public properties
/// <summary>
/// The secure string instance captured so far.
/// This is the preferred method of accessing the string contents.
/// </summary>
public SecureString SecureText
{
get
{
return _secureEntry;
}
set
{
_secureEntry = value;
}
}
/// <summary>
/// Allows the consumer to retrieve this string instance as a character array. NOte that this is still
/// visible plainly in memory and should be 'consumed' as wuickly as possible, then the contents
/// 'zero-ed' so that they cannot be viewed.
/// </summary>
public char[] CharacterData
{
get
{
char[] bytes = new char[_secureEntry.Length];
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.SecureStringToBSTR(_secureEntry);
bytes = new char[_secureEntry.Length];
Marshal.Copy(ptr, bytes,0,_secureEntry.Length);
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(ptr);
}
return bytes;
}
}
#endregion
#region ProcessKeyMessage
protected override bool ProcessKeyMessage(ref Message m)
{
if (_displayChar)
{
return base.ProcessKeyMessage(ref m);
}
else
{
_displayChar = true;
return true;
}
}
#endregion
#region IsInputChar
protected override bool IsInputChar(char charCode)
{
int startPos = this.SelectionStart;
bool isChar = base.IsInputChar(charCode);
if (isChar)
{
int keyCode = (int)charCode;
// If the key pressed is NOT a control/cursor type key, then add it to our instance.
// Note: This does not catch the SHIFT key or anything like that
if (!Char.IsControl(charCode) && !char.IsHighSurrogate(charCode) && !char.IsLowSurrogate(charCode))
{
if (this.SelectionLength > 0)
{
for (int i = 0; i < this.SelectionLength; i++)
_secureEntry.RemoveAt(this.SelectionStart);
}
if (startPos == _secureEntry.Length)
{
_secureEntry.AppendChar(charCode);
}
else
{
_secureEntry.InsertAt(startPos, charCode);
}
this.Text = new string('*', _secureEntry.Length);
_displayChar = false;
startPos++;
this.SelectionStart = startPos;
}
else
{
// We need to check what key has been pressed.
switch (keyCode)
{
case (int)Keys.Back:
if (this.SelectionLength == 0 && startPos > 0)
{
startPos--;
_secureEntry.RemoveAt(startPos);
this.Text = new string('*', _secureEntry.Length);
this.SelectionStart = startPos;
}
else if (this.SelectionLength > 0)
{
for (int i = 0; i < this.SelectionLength; i++)
_secureEntry.RemoveAt(this.SelectionStart);
}
_displayChar = false; // If we dont do this, we get a 'double' BACK keystroke effect
break;
}
}
}
else
_displayChar = true;
return isChar;
}
#endregion
#region IsInputKey
protected override bool IsInputKey(Keys keyData)
{
bool result = true;
// Note: This whole section is only to deal with the 'Delete' key.
bool allowedToDelete =
(
((keyData & Keys.Delete) == Keys.Delete)
);
// Debugging only
//this.Parent.Text = keyData.ToString() + " " + ((int)keyData).ToString() + " allowedToDelete = " + allowedToDelete.ToString();
if (allowedToDelete)
{
if (this.SelectionLength == _secureEntry.Length)
{
_secureEntry.Clear();
}
else if (this.SelectionLength > 0)
{
for (int i = 0; i < this.SelectionLength; i++)
_secureEntry.RemoveAt(this.SelectionStart);
}
else
{
if ((keyData & Keys.Delete) == Keys.Delete && this.SelectionStart < this.Text.Length)
_secureEntry.RemoveAt(this.SelectionStart);
}
}
return result;
}
#endregion
}
}
我可以通过添加以下内容来检测何时按下 Tab
:
case (int)Keys.Tab:
到switch(KeyCode)
块。但是,我不知道如何手动调用它通常具有的 "Select Next Control By Tab Index" 效果。
在这种情况下添加 SelectNextControl((Control)this, true, true, true, true);
似乎也不起作用。
在您的 IsInputKey 覆盖中,只需检查 Tab 键:
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Tab) {
return false;
}
// your code ...
}