Introduction
I’ve been writing iOS apps in Xamarin for a while and have been wanting to try Xamarin forms, there’s a problem I needed to solve and here is my first journey onto the Xamarin Forms land
Problem
I have been creating a few new accounts on the Internet that require the use of complex password recently and my existing sets of passwords are no longer/or only barely enough to pass the password strength checkers.
I needed a solution that could
a. allow me to come up with more secure password and
b. be easy enough to remember
My solution
Over the years, the idea of remembering one password and use a set of algorithm to generate passwords for all sites has been catching on. After seeing this article I really wanted to adopt the same system, the problem is I always forget the search term.
One day, I came across this article on Charles Leifer blog, we had the same problem and created a web service for his password generator.
I on the other hand, wish my algorithm to stay offline and in my control, and since I have a spare smartphone that I do not use, I decided to convert it into my special Password Generator which I will now have to carry around with me.
Background
Technology used: Xamarin Forms, .NetStandard
Techniques used: Dependency Injection (there are a lot of great articles on code project on this topic)
The Basic Idea
The basic idea here is to convert a common, easy to remember master string (ie. 'Password') into a more complex, harder to crack, impossible to remember password for specific websites/service.
The way to achieve it is simple,
- Take the master string as key,
- Add on to a specific salt, my convention here is to use the website name
- Encrypt it using SHA
- Since SHA returns all letters and numbers, I create a map of all available characters and translate using that map
- Verify the generated password meets the requirement
- Add additional character to fulfill the requirements
Code Structure
My project has the following components:
Core - Handles the password generation and storage of password scheme, it's a .NetStandard library
Core.Test - Unit tests to make sure the generated passwords are consistent and meet the requirement
PasswordManager (Portable) - Created for Xamarin Forms, I shall refer to this as "The PCL" from now on. It is the backbone of this Xamarin forms application. Both the Android and iOS project launches the App from the PCL
PasswordManager.Android - Android project
PasswordManager.iOS - iOS project, ignore since I don't have iOS developer subscription
Converting the PCL to .NetStandard library
I've been using Xamarin to write iOS in the past bit, it caught me by surprise that I could not add any framework dll reference to the Xamarin Forms portable library, which is a problem because it means I could not use System.Security.Cryptography namespace.
What's the solution? Apparently it is to use a .NetStandard library instead. That is why the Core project needs to be a .NetStandard library.
However, I could not simply add the .NetStandard library back to the PCL, it would not compile.
So we would have to convert the PCL to target .NetStandard
Which involved three extra steps as outlined here
- Use Nuget to remove Xamarin Forms from the solution
- Right click on the PCL and open the property window
- Target .NetStandard
- Select at least .Net Standard 1.3 to include Cryptography namespace
- A project.json file should have been generated, click on it to edit
- Under Frameworks, add the following line under frameworks
"imports": "portable-net45+win8+wpa81+wp8"
So this is about what the file would look something like
{
"supports": {},
"dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.0",
},
"frameworks": {
"netstandard1.4": {
"imports": "portable-net45+win8+wpa81+wp8"
}
}
7. Using Nuget, add Xamarin Forms back to the solution
Using the code
Password generation
Password generation is simple, simply create an instance of the PasswordGenerator like so
var passwordGen = new PasswordGenerator(PasswordRequirements.SymbolRequired | PasswordRequirements.UpperCaseRequired | PasswordRequirements.NumberRequired);
and create the password by calling
var password = passwordGen.GeneratePassword(sourceKey, salt, minimumLength);
Once again, here are the steps the PasswordGenerator takes
- Take the master string,
- Add on to a specific salt, my convention here is to use the website name
- Encrypt it using SHA
- Since SHA returns all letters and numbers, but I needed to use symbols, I create a map of all available characters and translate using that map
- Verify the generated password meets the requirement
- Add additional character to meet unmet requirements
Storing Password scheme
Why?
Now we have a password generated with different options, how do we remember what the options were? One option is to try all combinations. Try doing that ten times. Remember, the goal here is to create a password that is hard for computer to guess.
So we need to store the password scheme somehow, one benefit of storing a password per website/service is now we can write additional logic to check if two services are really the same.
For example, we don’t want to generate a different password for “Facebook” vs “facebook”
Ok, how?
For storage, I have chosen Sql-net-PCL.
To persist our password scheme, we need to create the database first
SqliteStorage.InitializeStorage(IoCProviders.GetProvider<IKnowStorage>().GetStoragePath(), databaseName);
Then we can store the appropriate settings using
ServicePersistor.Persist(serviceName, requirement);
So now we can generate password, store the options used to generate the password and we can retrieve password scheme using
var serviceEntity = ServicePersistor.GetPasswordSettings(serviceName);
Simple, huh?
What's this IoCProviders?
First challenge anyone would enounter is where would the database live?
iOS and Android have different file systems, I needed each platform to give me a location that I can use to store the db file.
Since the Core project is made to work with both iOS and Android, it doesn’t know about these platform-specific intricacies. How could I possibly know where to store/look for these files?
This is where dependency injection comes in, and there are tons of articles about this on Codeproject.
The idea is I can define a interface in Core that allows specific implementation detail to be created within the platform specific projects and I can use these implementation to perform platform-specific tasks.
The IoCProviders
here is a simple dictionary to keep track of these implementations.
Here’s the IoCProviders(Naming is hard)
in all of its glory
public class IoCProviders
{
private static IDictionary<Type, object> _providers;
private static IDictionary<Type, object> Providers
{
get
{
if (_providers == null)
{
_providers = new Dictionary<Type, object>();
}
return _providers;
}
}
public static void Register<TType>(object provider)
{
Providers[typeof(TType)] = provider;
}
public static TType GetProvider<TType>()
{
return (TType)Providers[typeof(TType)];
}
}
What about Mobile?
I have my way to generate password, and I can store it, how do I actually use it?
Well, I did promise an app didn't I.
I have chosen to use Xamarin Forms for curiosity’s sake.
To be honest, I wasn't quite looking forward to write user interface in XAML but I changed my mind after this experience.
What the app looks like
The App workflow looks like this
- Enter master password
- Enter service name
- Make sure settings are correct
- Get password
- Store the given password scheme for the service
- Copies password to clipboard (Platform specific)
- Notifies user password has been copied (Platform specific)
- User may choose to generate a new password with different settings
(If they chose the same setting, the same password will be generated again)
And here’s what the App looks like
What about Code?
What I have discovered is that XAML provides a real nice way of visualizing the control flow, once I have a ViewModel created
ViewModel = new PasswordRequestViewModel();
Controlling UI behaviour becomes a matter of setting using properties of PasswordRequestViewModel()
.
Here is an annotated view of what each of these variables control
MasterPassword
– Text value of the master password textbox ShowOrHideMasterPasswordTitle
– Title of the Show button ServiceName
– Text value of the Service name textbox IncludeNumbersString
– Title of the Include Numbers button IncludeSymbolsString
– Title of the Include Symbols button IncludeUppercaseString
– Title of the Include Upper case button PasswordVisible
– Controls whether the password field will show CreateNewPassword
– Controls visibility of the generate new password button which isn’t shown on the diagram
Here’s an example implementation for one of the properties
private string showOrHideMasterPasswordTitle;
public string ShowOrHideMasterPasswordTitle
{
get
{
return showOrHideMasterPasswordTitle;
}
set
{
if (showOrHideMasterPasswordTitle != value)
{
showOrHideMasterPasswordTitle = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ShowOrHideMasterPasswordTitle"));
}
}
}
And here’s what it looks like in XAML
<Button Text="{Binding ShowOrHideMasterPasswordTitle}" BackgroundColor="Transparent" Clicked="ShowHide_Clicked" />
I won’t get in details about the Clicked event, but that’s basically where visibilities and title of buttons get changed.
Come on, no checkbox?
One annoyance here is Xamarin Forms does not come with built in Checkbox/Radio boxes, I guess it's because iOS doesn't really like them. I took the lazy way out and used buttons instead.
For example, this is what the Include Uppercase button looks like
I would update the text in click events by changing the value of IncludeUppercase
private bool includeUppercase;
public bool IncludeUppercase
{
get { return includeUppercase; }
set
{
if (includeUppercase != value)
{
includeUppercase = value;
IncludeUppercaseString = value ? "[x] Include Upper case" : "[ ] Include Upper case";
}
}
}
IncludeUppercase
here is the real deal, whereas IncludeUppercaseString
is only used for UI
Platform specific implementation
I talked about platform specific implementations, it really is simple things that cannot be written in common code.
For example, iOS and Android has their own APIs for handling clipboard, Android has Toast, iOS has local notification.
Which is why I have the following interfaces
public interface ICopyToClipboard
{
void CopyToClipboard(string value);
}
public interface IKnowStorage
{
string GetStoragePath();
}
public interface IProvideNotifications
{
void Notify(string title, string message);
}
And the implementations are simple. For Android
public class ClipboardProvider : ICopyToClipboard
{
Context FormContext;
public ClipboardProvider(Context context)
{
FormContext = context;
}
public void CopyToClipboard(string value)
{
ClipboardManager clipboard = (ClipboardManager)FormContext.GetSystemService(Context.ClipboardService);
ClipData clip = ClipData.NewPlainText("Clipboard", value);
clipboard.PrimaryClip = clip;
}
}
public class NotificationProvider : IProvideNotifications
{
Context FormContext;
public NotificationProvider(Context context)
{
FormContext = context;
}
public void Notify(string title, string message)
{
Toast.MakeText(FormContext, message, ToastLength.Short).Show();
}
}
public class StorageProvider : IKnowStorage
{
public string GetStoragePath()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
}
These implementations are passed into the App and the app registers them with the IoCProviders
public App
(
IKnowStorage storageProvider,
ICopyToClipboard clipboardProvider,
IProvideNotifications notificationProvider
)
{
InitializeComponent();
IoCProviders.Register<IKnowStorage>(storageProvider);
IoCProviders.Register<ICopyToClipboard>(clipboardProvider);
IoCProviders.Register<IProvideNotifications>(notificationProvider);
MainPage = new PasswordManager.MainPage();
}
One Last Thing
When your app is in the background, and a random person walks by, you probably do NOT wish that person to open the app and see your master password. That is why I clear password and Master password whenever the app is resumed.
Xamarin Forms provides a nice method to override
protected override void OnResume()
{
((PasswordManager.MainPage)MainPage).ClearEnteredData();
}
So to recap, this is how the Mobile app code works
- Create instances platform specific Storage, Notification and Clipboard Providers
- Register the providers with IoCProviders
- Start App with MainPage
- XAML file describes the layout of the app, it defines the labels, and texts and events
- The control properties such as Title, Visibility are bound to variables in PasswordRequestViewModel
- Click events toggles the title, visibility and text values of the controls
Points of Interest
For me the real big question is, is this safe? How can I make it really safe?
I wanted to create a different database (with encrypted filename of course) for one master password, but I felt that’s leaving at least a bit of a trace for a potential attacker and I didn’t like that.
So now I use the same db for everything, leaving absolutely no trace, if I needed a different password, I could always append something to the master.
On the other hand, they also would have to figure out my username, maybe this is a motivation to not use the same set of usernames on every website?
This is really an experimental project for me, I expect everyone would have a slightly different idea of a secure password (for example, maybe the length of the password could be adjustable) Feel free to tweak to fit your liking, in fact I encourage it. I'm a big fan of tweaking to a specific need as opposed to creating a generic solution that tries to make everyone happy.
Acknowledgement
I'd like to thank everyone who write these amazing articles on Code Project. I learned so much from these articles early in my career, and this time I finally found something worth writing about.
Special acknowledgement to Charles Leifer, I really enjoyed your Saturday project ideas and it really encouraged me to try something like this myself
Source Code
Download PasswordManager.zip
History
June 17, 2017 - Cleaned up the language
May 22, 2017 – Initial Draft