Click here to Skip to main content
15,884,836 members
Articles / Programming Languages / C#
Article

Password Manager (.NET)

Rate me:
Please Sign up or sign in to vote.
4.67/5 (18 votes)
20 Oct 2008CPOL2 min read 113.4K   2.4K   70   7
Password manager application in .NET

Introduction

I wanted for some time to write a very simple password keeper for personal use. I'm posting it in case someone else finds it useful. I think it has some interesting ideas.

Once the username/password is inputted, it's kept encrypted. The way to use it: either by drag and drop (this is useful for HTML based forms) or SendMessage(WM_SETTEXT,...) buttons. You can look at the tool tips for each button.

So the password is never seen in the program itself in plain text unless you use the password or import previous passwords. No copy/paste to/from clipboard.

The app minimizes to a system tray. It has a hotkey (CTRL+F12). During startup, it asks for a password. When used for the first time, it will use this password to encrypt the data. Once you add your passwords, it's a good idea to backup the file to a safe location.

Notes

  • In most cases, the sensitive information is cleared right away (doesn't mean it's a 100% sure way) after it's not needed anymore through Array.Clear. But when dragging/sending the info to another window or when importing from another file, user and password is decrypted into a String and not cleared because String is immutable. So it's left to the GC.
  • Set the appropriate NTFS permissions on the application's directory, that's where the password file will be.
  • It's a good idea to modify the code that derives the encryption keys (add different iteration counts for hash, etc.) so it will be different from the version included with this article.
  • Use some .NET obfuscator. For example, at least the basic version that comes with Visual Studio 2003 (Dotfuscator community edition).

Code Snippets

The hotkey is registered and used through P/Invoke:

C#
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, Int32 id, 
                                   UInt32 fsModifiers, UInt32 vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, Int32 id);

Then actual WM_HOTKEY message is handled in WndProc:

C#
protected override void WndProc(ref Message m)
{
  if (m.Msg == 0x0312) //WM_HOTKEY
  {
    Visible = true;
    WindowState = FormWindowState.Normal;
    Activate();
  }
  base.WndProc(ref m);
}

The username and password use different encryption algorithms from whole file encryption. The keys and ivs are derived for two algorithms through PasswordDeriveBytes:

C#
pdb = PasswordDeriveBytes(txtPass.Text, salt, "SHA512", 1000)

keyRij = pdb.GetBytes(32);
key3des = pdb.GetBytes(24);

ivRij = pdb.GetBytes(16);
iv3des = pdb.GetBytes(8);

In most cases, the sensitive information is cleared right away after it's not needed anymore through Array.Clear. But when dragging/sending the info to another window, it's decrypted into a String and not cleared because String is immutable.

C#
string val =//user or pass.
IntPtr ptr = Marshal.StringToCoTaskMemAuto(val);
SendMessage(hWnd, 0x000C, 0, ptr.ToInt32());
Marshal.FreeCoTaskMem(ptr);
//
DoDragDrop(val, DragDropEffects.Copy);

For SendMessage case in mouse button down I've set Capture = true. Then in mouse button up event the Capture is set to false. And actual target window is found through P/Invoke.

C#
[DllImport("user32.dll")]
private static extern bool ScreenToClient(IntPtr hWnd, ref SeqPoint pt);
[DllImport("user32.dll")]
private static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(SeqPoint pt);        
[DllImport("user32.dll")]
private static extern IntPtr 
   RealChildWindowFromPoint(IntPtr hWndParent, SeqPoint Point);

The actual code to find the target window:

C#
private IntPtr FindTargetWindow(Point pt)
{
  SeqPoint seqpt = new SeqPoint();
  seqpt.x = pt.X;
  seqpt.y = pt.Y;
  IntPtr hWnd = WindowFromPoint(seqpt);

  //it's our window!
  if(Bounds.Contains(pt))
    return this.Handle;

  if (hWnd.ToInt64() != 0)
  {
    IntPtr hParent = GetParent(hWnd);
    if(hParent.ToInt64() != 0 && 
        ScreenToClient(hParent, ref seqpt))
    {
      hParent = RealChildWindowFromPoint(hParent, seqpt);
      if(hParent.ToInt64() != 0)
        hWnd = hParent;
    }
  }
  return hWnd;
}

When selecting the target window, there is a selection frame drawn for the target window. This is accomplished as follows:

C#
[DllImport("gdi32.dll")]
private static extern int GetBkColor(IntPtr hdc);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out SeqRect rect);

private void FrameTargetWnd()
{
  Point pt = Cursor.Position;
  IntPtr hWnd = FindTargetWindow(pt);
  if(hWnd.ToInt64() != 0)
  {
    SeqRect rc;
    if(GetWindowRect(hWnd, out rc))
    {
      Rectangle rect = new Rectangle(rc.left, 
         rc.top, rc.right - rc.left, rc.bottom - rc.top);
      if(rect != previousRect)
      {
        Graphics g = Graphics.FromHwnd(hWnd);
        IntPtr hDC = g.GetHdc();
        if(hDC.ToInt64() != 0)
        {
          try
          {
            if(previousRect.Height > 0 
                  || previousRect.Width > 0)
              ControlPaint.DrawReversibleFrame(previousRect, 
                  drawFrameBkColorPrev, FrameStyle.Dashed);
            //prevent our window from being the target
            if(hWnd != this.Handle)
            {
              //get color for the target background window
              drawFrameBkColor = Color.FromArgb(GetBkColor(hDC));
              ControlPaint.DrawReversibleFrame(rect, 
                   drawFrameBkColor, FrameStyle.Dashed);
              //save current frame rect and bk color, 
              //so it can be reset with next call 
              //or in mouse up event
              previousRect = rect;
              drawFrameBkColorPrev = drawFrameBkColor;
            }
            else
            {
              //if it's our window just reset 
              //previous rect's size to 0
              //so it won't be drawn next time
              previousRect.Size = new Size(0,0);
            }
          }
          finally
          {
            g.ReleaseHdc(hDC);
            g.Dispose();
          }
        }
      }
    }
  }
}

Everything else is just standard .NET stuff.

Disclaimer

THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

History

  • 17th August, 2003: Initial post
  • 18th October, 2008: Download file updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralThank You !!! Pin
Charles Cavalcante15-Jul-10 8:41
Charles Cavalcante15-Jul-10 8:41 
GeneralSecureString Pin
Qistoph22-Oct-08 1:32
Qistoph22-Oct-08 1:32 
GeneralRe: SecureString Pin
Leon Finker22-Oct-08 14:28
Leon Finker22-Oct-08 14:28 
Hi,

When i wrote the code in 2003 there was no SecureString. At that time i came up with the "manual clearing" of the string contents' buffer. Also, in current code, while in-memory the data is encrypted.

With SecureSrting there still has to be a place where data needs to be in plain text in order to get into the SecureString. Code has to be rewritten away from built-in XML reader/writer that i used. In my case also, the data has to be in plain text for a very short period when it actually needs to be supplied to a call to Control.DoDragDrop/SendMessage otherwise it is in encrypted form in-memory.

Also, I'm not clear (if not using String) how to get from SecureString which returns IntPtr (Marshal.SecureStringToBSTR) to the data needed by DoDragDrop that Control class exposes. But this can be worked around, if needed, by going to win32 OLE D&D directly. In the end i didn't see this as worth the excersise just to prevent the short time exposure in memory of the data. I was really trying to be perfectionist. In reality data has to be in plain mode for short time period anyway in order for drag & drop and SendMessage functionality to work (plus on the target of the drag/drop or sendmessage).

Thank you for the suggestion!
QuestionGood idea! Pin
manfbraun23-Apr-06 9:11
manfbraun23-Apr-06 9:11 
AnswerRe: Good idea! Pin
Leon Finker23-Apr-06 15:29
Leon Finker23-Apr-06 15:29 
Generalhi Pin
Anonymous7-May-04 9:30
Anonymous7-May-04 9:30 
GeneralRe: hi Pin
GabbleWu11-Jun-04 15:57
GabbleWu11-Jun-04 15:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.