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

CSecureEditEx - A More Secure Edit Control

0.00/5 (No votes)
17 Apr 2005 1  
CSecureEditEx controls are resistant to password revealers. Passwords aren't visible in the process memory.

Index:

  • Introduction
  • Features and Limitations
  • Using the Control
  • Technical Background / How It's Working?
  • References
  • Version History

    Introduction

    Almost all Windows applications dealing somehow with passwords are using the standard Windows edit controls with the password flag set. Unfortunately, these controls aren't that secure by default. This article is an attempt to improve its security.

    In Windows 95 and 98, applications were able to send a WM_GETTEXT message to the edit controls to get the password, just like getting the text out of a normal edit control. This itself isn't bad, but Windows allowed you to send WM_GETTEXT messages to other applications, too. You just sent such a message to all other windows and easily get all passwords.

    In Windows NT/2000/XP, this bug has been fixed. You cannot use WM_GETTEXT messages any more to get the passwords out of other applications (still working when the application owning the control sends the message). But some people developed new methods to get the sensitive texts. One approach for example is injecting some code into the target process using Windows hooks. The injected code is in the process memory of the target application then and is able to call the WM_GETTEXT messages. The code then can do whatever it wants with the password. For implementation details of this method, see [1]. So, the password edit controls in Windows NT/2000/XP aren't that secure either.

    In my previous article [2], I've solved this problem already. Now, the CSecureEditEx control goes one step further: process memory protection.

    The Windows standard edit controls and my previous CSecureEdit control store the passwords as plain-text in the process memory. My previous class did protect the window of the control: WM_GETTEXT messages didn't work. Anyway, even the improved control stored the password plainly in the memory.

    If Windows caches your process into the swap file, you're out of luck with these controls: the password is written plainly to the swap file, possibly lying around there for days. Of course, it's not a simple task for an attacker to find the password in the swap file, but why not making it even harder for him? The new CSecureEditEx control does this: even if Windows caches your process to disk, the passwords aren't visible in plain-text.

    You'll see that the CSecureEditEx control not only introduces the new process memory protection, but also some limitations. That's the main reason why I'm posting a new article and not just updating the CSecureEdit control.

    Features and Limitations

    Features of the CSecureEditEx control:

    • None of the many available window spies are able to read the entered password.
    • Removing the ES_PASSWORD style doesn't affect CSecureEditEx controls.
    • CSecureEditEx controls look like normal Windows edit controls.
    • User can insert a character anywhere (i.e. use cursor keys).
    • User can delete characters.
    • User can paste text into CSecureEditEx controls.
    • User cannot copy text out of CSecureEditExs.
    • Pressing Shift-Home or Shift-End clears the contents of the control.
    • Very easy to implement and use.

    Limitations:

    • Selections aren't possible. The user cannot select character ranges in the edit control.
    • Your CString DDX functions to the control won't work any more.

    The selection limitation is a natural consequence of the internal processing of keys and edit control changes. If selections would be possible, the control couldn't decide which part of the text has changed or deleted.

    But since we're making password edit controls, selections aren't that required anyway. Users normally delete the whole entered text when they notice that they typed some wrong key. For this, most people use Shift-Home to select the whole text. Exactly this combination clears the whole control, so there aren't any real usability disadvantages.

    Using the Control

    Using the CSecureEditEx control is pretty simple. Just follow these steps:

    1. Incorporate the SecureEditEx.cpp and SecureEditEx.h files into your project.
    2. #include the SecureEditEx.h in the header file of your dialogs/views/etc. which should use the new control.
    3. Replace the CEdit variable of the control by CSecureEditEx.
    4. Make sure your password edit control has the ES_PASSWORD set (in resource editor).

    Done! That's all you have to do! No additional initialization or something like this is needed.

    The last step is optional. It won't lower security if you don't set this flag, but some context menu operations like copying the text are possible then (they won't work, therefore it would be just nice to show those items grayed). I recommend enabling the ES_PASSWORD style.

    Now, how do you get the entered password out of the control, if the WM_GETTEXT message doesn't work any more? DDX to CStrings doesn't work any more, too. You have to use the following member function:

    LPTSTR CSecureEditEx::GetPassword()

    This returns the entered text as a LPTSTR pointer. Be very careful what you are doing with it! Don't just copy it to some other location, the whole security improvement would be lost then! You are of course allowed, for example, to hash the text with a one-way hash function (SHA-1) and store the hash.

    When you've processed the password, you need to free the pointer, i.e. securely erase and free the memory! Use the following member function to accomplish this:

    void CSecureEditEx::DeletePassword(LPTSTR lpPassword)

    Pass the LPTSTR pointer returned by the GetPassword() function to this function. It will securely erase and free the memory. The lpPassword pointer then is invalid after the execution of the function.

    Mostly you will want to set a password as default. The WM_SETTEXT message doesn't work, you need to call the following function in order to set the current password:

    void CSecureEditEx::SetPassword(LPCTSTR lpPassword)

    This sets the current password to the string lpPassword points to. If you pass NULL as parameter, the edit control is cleared (i.e. simply no text).

    Technical Background / How It's Working?

    The CSecureEditEx internally keeps an array of pointers to single TCHARs. These TCHARs are XORed with some fixed character that is generated randomly in the constructor of the class. So, the characters aren't just spreaded over the process memory, they are additionally XORed with some random character.

    When the user presses a key, the control looks what has changed.

    If the contents of the control are shorter than before, the user has deleted something. In this case, it gets the current cursor position and calculates how many characters have been deleted. It then frees the internal memory pointers (first sets the single characters to 0) and removes them from the pointers list.

    If there are more characters than before, those characters are extracted and added: first allocate the memory for the characters, XOR them with the appropriate value and insert the pointer to this location to the pointers list.

    As you can see, the control uses the cursor position to see what happened. In order to get this working correctly, the user must not select any range of characters. If he would do this, we couldn't determine the operation and changed characters correctly. Therefore, the control prevents all selecting methods (selecting using Shift and cursor keys, selecting using the mouse, etc.)

    To clear the whole control, the user can just press Shift-Home or Shift-End. This clears the control.

    References

    1. Brian Friesen: PasswordSpy - Retrieving lost passwords using Windows hooks.
    2. Dominik Reichl: Secure Edit Controls - Secure Edit controls that are resistant to password revealers.

    Version History

    • 2005-04-16: v1.0

      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