SecurePasswordTextBox阻止选项卡并输入密钥

时间:2018-02-08 23:09:14

标签: c# winforms controls securestring

我使用SecurePasswordTextBox的修改版本在我的WinForms应用程序上创建安全的输入控件(是的,我知道它很大程度上没有意义,但我们的一位客户坚持认为不应该有敏感数据在内存中作为字符串处理。

然而,出于某种原因。在选择控件后,这似乎打破了表单的tabenter键。我们不能再使用它们在控件之间跳转。我该如何解决这个问题?我尝试使用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)区块。但是,我不知道如何然后手动调用&#34;选择下一个按控制选项卡索引&#34;它通常会产生的影响。

在这种情况下添加SelectNextControl((Control)this, true, true, true, true);似乎也无效。

1 个答案:

答案 0 :(得分:1)

在IsInputKey覆盖中,只需检查 Tab 键:

protected override bool IsInputKey(Keys keyData) {
  if (keyData == Keys.Tab) {
    return false;
  }

  // your code ...
}