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

Windows Mobile Password Safe

0.00/5 (No votes)
12 Jan 2009 22  
A password safe with a touch screen UI introducing Fluid Controls.

PasswordSafeSource

MobilePasswordSafe/Set2.png

MobilePasswordSafe/Set3.png

MobilePasswordSafe/Set4.png

MobilePasswordSafe/Set5.png

Introduction

Password Safe is a .NET 2.0 Mobile application that allows you to keep your passwords in your mobile secured with the top secure AES encryption. It provides a nice touch surface with gestures, and can be completely used without a stylus, except when you're writing or editing new passwords.

First of all, when you download the exe, you just need to put the DLL and the exe file to any location of your choice. Then, you can start the exe after two security warnings. The password.pws file is optional, and can be placed in the “\My Documents” folder, and contains a demo database just to play around. This database has no password.

How to use Password Safe

The first time you start Password Safe, a welcome screen appears, and an empty default database is created. As the next step, you should create a password for it using the "Change Password" button. Then, you can select a category of passwords. After selecting a category, it appears empty, and you can use the "+" button on the header at the right to create a new one. Just type in a field. You'll notice that the Undo (blue button) and the Save button at the bottom get activated. Now, you can either undo your changes or save them. They are automatically saved when you log out or close Password Safe. If you want to delete a password, go to Details, press the "-" button on the header, and confirm the message dialog.

The Search button becomes active when you are are in a category list. You can minimize the contents of the list by opening the Search panel. In this panel, you can type like you type an SMS. Only those items that contain a part of the possible text you typed remain in the list.

If you want to minimize the choice of categories, click the "+" button on the header to add or remove categories. Don't worry if you remove a category. The passwords don't get lost and are still available in the "All Passwords" category, and you can add the category back to the list at any time.

In future releases I will add the possibility to create and edit our own categories. That's why the categories are all stored in the password.pws database.

Background

In December, I bought a new mobile phone, the Xperia x1. Shortly before Christmas, I decided to quickly write a simple password safe to maintain the various passwords I own, both at job and at home. But as always, I could not write just simple programs, and so I wasn’t satisfied with the features that were available with the .NET Compact Framework for Windows Mobile. It didn’t like good, and it was hard to use without a stylus. Therefore, I decided to create my own fancy controls.

Due to the lack of a better name, I currently call them Fluid Controls, but most probably, I will rename them to a name that sounds good and is not already copyright protected. I guess iControl would not be possible ;-)

The controls that I developed are not windows components which are actually “windows”, and so they don’t have their own graphics and message system. They are more like Silverlight controls, which are completely maintained different.

The heart of the controls is the FluidHost class.

It’s the connection between a Windows Form and the Fluid Controls. It listens to all events, like mouse or keyboard events, and translates them to send them to the controls. It also recognizes gestures.

As soon as a gesture is recognized, it sends an OnGesture event to the root level controls (which will redirect them to their child controls, and so on). In this event, a control can decide to do something with this event, or to cancel this event.

The following snippet is from the ScrollContainer class which is the base class for all controls that offer scrolling:

public override void OnGesture(GestureEventArgs e)
{
    if (e.IsPressed)
    {
        pressedGesture = e.Gesture;
        switch (e.Gesture)
        {
            case Gesture.Up:
            case Gesture.Down:
                e.Handled = true;
                break; 

            case Gesture.Canceled:
                e.Gesture = Gesture.None;
                e.Handled = true;
                break; 

            default:
                IsDown = false;
                CanScroll = false;
                e.Handled = true;
                break;
        }
    }
    else
    {
        switch (e.Gesture)
        {
            case Gesture.Down:
                if (e.Distance > MinAutoScrollPixelDistance)
                {
                    e.Handled = true;
                    int speed = e.PixelPerMs;
                    if (speed > 0) BeginAutoScroll(-speed);
                }
                break; 

            case Gesture.Up:
                if (e.Distance > MinAutoScrollPixelDistance)
                {
                    e.Handled = true;
                    int speed = e.PixelPerMs;
                    if (speed > 0) BeginAutoScroll(speed);
                }
                break;
        }
    }

    if (MouseGesture != null) MouseGesture(this, e);
}

You can try the back gesture in Password Safe. Instead of pressing the Back button, you can wipe your finger from left to right and release it so it has the same effect.

Basically, when the host gets an input event, it redirects it to the root level controls, which will redirect them to their controls, and so on. The exception is the OnKeyPress event which is redirected to the top level control (maybe a textbox), and the top level control redirects the event down to the parent control (or not).

Painting

It’s almost the same as for the normal Windows controls, except that there is a FluidPaintEventArgs event. Remember that the Fluid Controls are not windows controls, and thus they don’t have their own canvas. Therefore, the controls get the Graphics of the host control and the FluidPaintEventArgs has a ControlBounds rectangle that specifies where the control has to paint itself. Due to performance issues, this area is not clipped, so it would be possible to paint outside this rectangle.

Another important property of FluidPaintEventArgs is Region. It contains the region that needs to be painted, and is the same as the region in Graphics.Clip. So, why would I add a separate property? Because, whenever you access the Graphics.Clip, it actually creates a copy of the Region. So, for example, the ListBox would create various regions whenever it checks if an Item is within the region. This is a huge performance penalty, so I added the Region property, which does not create a clone.

To check if a rectangle is dirty and needs to be painted, you can use the Region.IsVisible(rect) method:

private void PaintHeader(FluidPaintEventArgs pe)
{
    Rectangle bounds = GetHeaderBounds();
    Rectangle clip = pe.ControlBounds;
    bounds.Offset(clip.X, clip.Y);
    if (pe.Region.IsVisible(bounds))
    {
        if (!EnableDoubleBuffer)
        {
            PaintHeaderUnbuffered(pe);
        }
        else
        {
            PaintHeaderContentDBuffered(pe);
        }
    }
}

The ListBox

The ListBox derives from the ScrollContainer class which is a base class for all controls that support touch screen scrolling.

It will allow different data sources like any IList or a DataTable, but currently, only IList and IBindingList are supported. The advantage of IBindingList is that the ListBox gets informed whenever something has happened to the List, like adding or removing an item, or even modifying an item (if the developer doesn’t forget to notify the binding list by calling ResetItem()).

The List itself can contain any kind of class, simple strings, integers, or complex classes.

To display an item in the ListBox, Templates are used. A Template is a simple panel with an additional Item and ItemIndex property. It is possible to use different Templates for different classes. Therefore, you can specify either a BindTemplate event or override the OnBindTemplate method. In the first case, you get a TemplateEventArgs with the item for which to obtain a template, and you can specify the template for it on the TemplateEventArgs template property. In the latter case, the OnBindTemplate expects to return the template that it can use, with the index and the item as well as the default Template as parameters.

If you don’t use different Templates, you just need to specify a default Template property for the ListBox. This is how I did it in Password Safe.

How does a template get the data?

It doesn’t work automatically, and you have to program this manually. There are two ways to implement this. The first way that I’m using is to override the OnBindValue and or OnItemUpdate methods of a derived Template:

protected override void OnBindValue(object value)
{
    PWNameValue item = value as PWNameValue;
    if (item != null)
    {
        nameLabel.Text = item.Title;
        valueTb.Text = item.Value;
    }
    else
    {
        nameLabel.Text = "";
        valueTb.Text = "";
    }
}

This method occurs as soon as a the Item value of the Template changes. Note the word changes!

The other method, OnItemUpdate, however, occurs every time the Template is prepared for usage, not only when the Item changes:

protected override void OnItemUpdate(object value)
{
    DetailListBox lb = DetailListBox;
    bool isSelected = lb.SelectedItemIndex == this.ItemIndex;
    nameLabel.ForeColor = isSelected ? Theme.Current.ListSecondarySelectedForeColor : 
                          Theme.Current.ListSecondaryForeColor;
    valueTb.AllowEdit = Editable && (SelectedItemIndex == ItemIndex);
}

This can become handy when you need to modify some properties of your template depending on the current state of the list box item itself, as the above snippet from the source code shows.

The other way to assign the data is to use the DataBound event handler of the ListBox:

/// <summary>
/// Occurs after the Template was data bound
/// an the EndInit state is completed for the template.
/// </summary>
/// <example>
/// You can use this events to perform some actions that require
/// to raise an event, for instance to set the focus to a control like tbFirstName.Focus().
/// </example> 
public event EventHandler<TemplateEventArgs> DataBound; 

or, you override the OnDataBound method of a derived listbox. In the source code, I do not use this possibility.

Finally, if you don’t want to use any template, you can directly paint each item, by adding a PaintItem or PaintGroupHeader event handler to the ListBox, or override the OnPaintItem method of a derived ListBox.

I am using this possibility to paint a custom background for a template:

protected override void OnPaintItem(ListBoxItemPaintEventArgs e)
{
    if (e.IsSelected)
    {
        e.BackColor = theme.ListSelectedBackColor;
        e.ForeColor = theme.ListSelectedForeColor;
    }
    else
    {
        e.BackColor = theme.ListBackColor;
        e.ForeColor = theme.ListForeColor;
    } 
    
    if (e.Item is GroupHeader)
    {
        e.BackColor = theme.ListHeaderBackColor;
        e.PaintDefault();
        e.Handled = true;
    }
    else if (e.IsSelected)
    {
        e.BorderColor = e.BorderColor;
        e.PaintHeaderBackground();
        e.PaintDefaultBorder();
        e.BackColor = Color.Transparent;
        e.PaintTemplate();
        e.Handled = true;
    }
    base.OnPaintItem(e);
}

Now, you have a ListBox that can show any kind of data.

Additionally, there are some interfaces that the ListBox recognizes for an Item:

  • ItemHeight

    Allows you to specify a distinct height for an item.

  • IGroupHeader

    Specifies a group header which separates items, e.g., by alphabet, like it does for the passwords (see pictures).

  • IColorGroupHeader

    Specifies a group header that also specifies in what background color the header should be painted, other than the predefined color.

The simplest ways to add a group header to the list is to add a GroupHeader class with a title to the list:

private NotifyList AddHeaders(NotifyList passwords)
{
    NotifyList list = new NotifyList(); 
    string current = ""; 

    foreach (PasswordData d in passwords)
    {
        string c = d.Name.Substring(0, 1).ToUpper(); 
        if (current != c)
        {
            current = c;
            list.Add(new GroupHeader(c));
        }
        list.Add(d);
    }
    list.ModifyChanged += new EventHandler(ListModifyChanged);
    return list; 
}

A DataSource for a ListBox is usually a BindingList<object> list. Why not a more specific class like BindingList<MyData>? Because, then you would not be able to add a group header. But, of course, you could create a MyData class and a derived MyGroupHeaderData class, then you would be able to specify a BindingList<MyData> and add some group headers.

As soon as a IGroupHeader is attached as the first item, the ListBox adds a header that is permanently visible and shows the last available group header. It also performs an overlapping as soon as a new group header is close to be the new header. It’s hard to explain, the best is to just try it out.

The ListBox show a scrollbar on demand, as soon as the TopOffset changes and disappears automatically after a delay.

Alpha-blending

It’s possible to use a fade effect for the disappearance of the scrollbar, and you can make the header transparent. But, I don’t use this since alpha-blending slows down the system. I will improve this by using DirectX 2D for alpha-blending functionalities instead of using methods from the GDI+ DLL.

The Panel

The Panel is a host for different controls, of course. Each control has a Anchor property which specifies how to layout the control within a Panel. There is currently no Docking property available. It does this by directly overriding the OnSizeChanged event of a control, but maybe, I’ll add it in a later version. The layout of the controls is smart, so the need to paint areas that are hidden by later controls is reduced, unless they are transparent.

A Panel also has the possibility to act like a window. Therefore, it has the Show, ShowMaximized, and Close methods available. As soon as you call Show, it appears in front of the previous controls with the specified bounds. If you call ShowMaximized, it’ll be maximized to full screen. More interesting thing is to add a ShowTransition parameter to the Show or ShowMaximized call. This parameter specifies that the panel should not just appear, but appear animated into the screen. There are various transitions possible, but currently, only FromBottom or FromTop are supported. The fade effect is simply too slow without DirectX 2D. And, I did not need to use FromLeft or FromRight. I will also add some other effects, like page turning, zooming, etc., as soon as I have the time.

void newCategoryButton_Click(object sender, EventArgs e)
{
    CategoriesPanel cp = CategoriesPanel.Instance;
    cp.UpdateData();
    cp.ShowMaximized(ShowTransition.FromBottom);
}

To speed up your panel, you should set EnableDoubleBuffer to true. This creates a separate bitmap and region to invalidate, and so the canvas is only repainted when its own region has become invalidated. EnableDoubleBuffer is smart, and does not always actually use a double buffer. It would make no sense to double buffer when it contains only one control that is already double buffered. On the contrary, it would cause a performance penalty to shift an image from one bitmap to another. The panel checks the situation, and only if it is adequate, will it create a double buffer.

Additionally, you can specify an Alpha value lower than 255, and the panel becomes transparent if you also use EnableDoubleBuffer. But note that alpha-blending is currently slow, and the bigger the panel is, the slower it will become.

The ButtonGroup

The ButtonGroup groups more buttons together. You can specify which corners of the ButtonGroup should be rounded.

The Header

The Header is, like the name says, a header control, which contains a text, a Backbutton on the left, and a ButtonGroup on the right.

The TransitionPanel

This Panel can contain multiple Controls, but only one control is displayed at once. You can use the ItemIndex and/or Item property to change the Control to be displayed. The interesting thing is that the TransitionPanel uses a transition to flip from one control to another.

The NavigationPanel

This is a combination of a Header and a TransitionPanel, which syncs the transition of the panel with the header. It also manages the BackButton automatically, and principally, it is being used to show hierarchical structures.

A NavigationPanel hosts Page panels.

The NavigationPanel has Back and Forward methods. Back navigates back to the previous Page, and Forward to the next level Page.

PageControl

This is a panel that is used for a navigation panel, and has additional properties to be maintained by the NavigationPanel:

  • BackButton specifies a different back button, if not to be maintained by the NavigationPanel.
  • Buttons contains the buttons to be displayed in the header as soon as the page becomes active.

Note that I intended to also add a fading animation between the old and new buttons as soon as a page flips, but there is the same performance problem with alpha-blending as mentioned before, so let’s look at what DirectX can do…

NumericPad

This is a compound panel that builds, like the name says, a numeric pad for different purposes.

MessageDialog

A predefined panel that has a text and two or less buttons at the bottom. Its purpose is to show simple dialogs with requests of two choices. You can use the MessageDialog.Show() method to quickly show the dialog. You can also open the dialog modal, so that a transparent empty panel is above the remaining screen and lets the other controls appear darker and not touchable. In that case, you must specify an event handler to decide what to do when one of these buttons is pressed. Here comes an example:

void delPasswordButton_Click(object sender, EventArgs e)
{
    passwordToRemove = passwordsListBox.SelectedPassword;
    if (passwordToRemove != null)
    {
        MessageDialog dialog = new MessageDialog();
        dialog.Message = "Delete Password?";
        dialog.Result += new EventHandler<Fluid.Classes.DialogEventArgs>(dialog_Result);
        dialog.ShowModal(ShowTransition.FromBottom); 
    }
} 

void dialog_Result(object sender, Fluid.Classes.DialogEventArgs e)
{
    switch (e.Result)
    {
        case System.Windows.Forms.DialogResult.OK:
            ListBuilder.Instance.DeletePassword(passwordToRemove);
            UpdatePasswords();
            this.GoBack();
            break;
    }
} 

Finally, I shortly mention the

  • Button
  • FlatButton
  • TextBox
  • Label

controls which are primary controls.

Notice, that I mostly reuse controls, even EventArgs. That’s because some delays appeared while I was playi… testing the scroll behavior. I figured out that the cause was the garbage collector. So for better performance, I created them either generally or first on demand.

private void EnsurePaintEvents()
{
    if (paintEvents == null) paintEvents = new FluidPaintEventArgs();
}

Animator class

This is the class that provides neat animations and is similar to Silverlight, though not that flexible. You have three kinds of animations: Linear, Acceleration/Deceleration, or Log. Acceleration/Deceleration does what the name says. If you specify a positive Acceleration property, the animation accelerates; with a negative value, it decelerates. The Log (arithmic) animation is logarithmic, and is best for visual effects that look like you are releasing a rubber band. You can see that kind of animation when you move the top position of a listbox down and release your finger, and then it jumps back to the default position.

GDI+ in the .NET Compact Framework

Unfortunately, some rendering methods that I need to paint my controls are missing in the Compact Framework, though the GDI+ DLL is part of Windows Mobile. Therefore, I use a custom GraphicsPlus class, with Graphics as parameter, that builds a wrapper to the now available methods, like drawing shapes etc. Not everything that the Windows Mobile GDI+ offers is truly possible. Sometimes, you get a NotImplemented exception, for instance, when you try to use a Region with a GraphicsPath. This does not work, so I had to do a workaround to create the glossy buttons, by creating actually two parts of a path, one for the top and one for the bottom, both with different gradients.

Designer

As the fluid controls are not window controls, there is no visual designer available. But since the target is Windows Mobile, you wouldn't create too sophistic UIs, and so the code to define the controls is not that complicated.

Password Safe

Something to mention about Password Safe itself.

It is designed to run on systems with a resolution of 480x800 pixels, but also works on smaller resolutions with 240x320 pixels, though some text might not be readable as the font is too small. Only the search panel that filters out passwords will not show up.

At the Category list, there is an edit button and an add (+) button on the header. When you press the edit button, a round button appears animated on each item on the left to provide an option to delete the item. As soon as you press this button, another button appears on the right to confirm the deletion. This looks nice, but is actually not very performant. The (+) button does the same, both adding and removing items. The iPhone like behavior is just a proof of concept that it is not very difficult to implement, and will be removed in later versions.

The passwords are saved in XML format which is encrypted using the top secure AES encryption.

Encryption

The .NET Framework offers a lot of different symmetric and asymmetric encryption algorithms, do does the Compact Framework for Windows Mobile. But, one important class is missing in the Compact Framework:

  • Rfc2898DeriveBytes

This class provides functionality to create key data from an arbitrary password string, which is required for every encryption algorithm. You cannot simply convert the password string to a byte[] array using, e.g., Encoding.Default.ToArray(password), since the key must be of a specific size. The size can vary by different blocks, and it depends on the algorithm you are using. For instance, the preferred AES or Rijndael algorithm requires a key size of 128, 256, 384, etc., but nothing in between. Therefore, you need an algorithm that encodes any string to a byte array of at least 128 bytes and not less or more.

Fortunately, this is what hashing algorithms do! So, as a replacement for the missing Rfc2898DeriveBytes, we can use a hash algorithm that belongs to the Compact Framework, and that creates a size that matches the requirements for the encryption algorithm. In this case, since we are using AES, we need a hash with a size of 128 or 256, and the qualified match is the MD5 algorithm. It is not the strongest though, and SH256 would be the better choice, but unfortunately, the Compact Framework does not include this hash algorithm, so we need to use MD5.

Here comes an example of how to implement encryption/decryption for Windows Mobile.

Final words

So, after almost 7000 lines of code, I present you my Christmas vacation project. As soon as I make a final decision for the final name of the controls, I will push them to CodePlex to keep you up to date on newer versions.

I hope you like my application, and of course, I would like to participate in the Microsoft Mobile Developer Contest 2008 :-)

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