Xamarin forms allow us to develop cross-platform (Windows Phone, Android and iOS) apps with a common UI project and with native look & feel. This common UI project can be a shared project or portable library.
Shared projects are used when common code must be shared among all the platforms and if needed allows the use of custom code targeting specific platforms with debug symbols whereas portable projects allow us to create common code irrespective of the platform and is limited to common features available in all the platforms. It doesn't allow developers to write code for a specific platform. This approach has both advantages and disadvantagoes. The advantages are the sharing of a library with other developers and the code changes are immediately reflected in the depedent projects. The disadvantages are that no-platform-specific code is allowed and is limited to common features of all the platforms it supports and cannot reference platform-specific libraries.
Recently I have been working on a project to develop native apps in all the three platforms (Windows Phone, Android and iPhone) with C# and Xamarin forms. One of the requirements is to use cryptography features to encrypt and decrypt user data based on the password supplied.
.Net provides exellent cryptographic features under the namespace System.Security.Cryptography. The intended use of this library is for .Net development in Windows. It cannot be used in Windows Phone and Silverlight and Xamarin portable forms cannot use them.
Some of the alternatives are:
- PCL Contrib: Community developed project. Supports cryptographic features such as AES, Derived key algorithms. The advantage is it uses the same namespaces as .Net cryptography. Not frequently updated: Portable Class Libraries Contrib.
- Bouncy Castle PCL: Portable Class Library version of Bouncy Castle Cryptography with many criptographic alogrithms: A modification of C# Bouncy Castle to be usable with PCL's.
- PCL Crypto: Portable Class Library. No proper documentation. Supports all the Xamarin platforms: Cryptography for portable class libraries.
The other work-around is to use some dependency injection with platform-specific code in each platform library and using it in common projects. Xamarin forms provide a minimum depedency feature using DependencyService. The only issue here is writing platform-specific code and it is time consuming: Accessing Native Features via the DependencyService.
I have decided to use the PCL Crypto library since it is easier and flexible to use. I'll explain how to configure and use PCL crypto with a sample project. The task is to encrypt and decrypt user passwords with the AES CBC algorithm using an AES 256bit cryptographic key. The key is generated from a combination of password and randomly generated salt using a PBKDF2 derived key algorithmic function.
Step 1
Create a Xamarin forms portable application.
Visual Studio creates the following 4 projects, one common portable and three platform-specific libraries.
Step 2
Install the PCLCrypto library with the Nuget tool.
Important: the PCL Crypto libraries must be added to each platform and common library. Common cryptographic code can be added in the common portable. Uncheck iOS library if you get an error during install.
Step 3
Create a cryptographic helper class in the Common Portable Library (CryptoForms).
Add the following code in Crypto.cs:
- using System.Text;
- using PCLCrypto;
- namespace CryptoForms
- {
- /// <summary>
- /// Common cryptographic helper
- /// </summary>
- public static class Crypto
- {
- /// <summary>
- /// Creates Salt with given length in bytes.
- /// </summary>
- /// <param name="lengthInBytes">No. of bytes</param>
- /// <returns></returns>
- public static byte[] CreateSalt(uint lengthInBytes)
- {
- return WinRTCrypto.CryptographicBuffer.GenerateRandom(lengthInBytes);
- }
- /// <summary>
- /// Creates a derived key from a comnination
- /// </summary>
- /// <param name="password"></param>
- /// <param name="salt"></param>
- /// <param name="keyLengthInBytes"></param>
- /// <param name="iterations"></param>
- /// <returns></returns>
- public static byte[] CreateDerivedKey(string password, byte[] salt, int keyLengthInBytes = 32, int iterations = 1000)
- {
- byte[] key = NetFxCrypto.DeriveBytes.GetBytes(password, salt, iterations, keyLengthInBytes);
- return key;
- }
- /// <summary>
- /// Encrypts given data using symmetric algorithm AES
- /// </summary>
- /// <param name="data">Data to encrypt</param>
- /// <param name="password">Password</param>
- /// <param name="salt">Salt</param>
- /// <returns>Encrypted bytes</returns>
- public static byte[] EncryptAes(string data, string password, byte[] salt)
- {
- byte[] key = CreateDerivedKey(password, salt);
- ISymmetricKeyAlgorithmProvider aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
- ICryptographicKey symetricKey = aes.CreateSymmetricKey(key);
- var bytes = WinRTCrypto.CryptographicEngine.Encrypt(symetricKey, Encoding.UTF8.GetBytes(data));
- return bytes;
- }
- /// <summary>
- /// Decrypts given bytes using symmetric alogrithm AES
- /// </summary>
- /// <param name="data">data to decrypt</param>
- /// <param name="password">Password used for encryption</param>
- /// <param name="salt">Salt used for encryption</param>
- /// <returns></returns>
- public static string DecryptAes(byte[] data, string password, byte[] salt)
- {
- byte[] key = CreateDerivedKey(password, salt);
- ISymmetricKeyAlgorithmProvider aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7);
- ICryptographicKey symetricKey = aes.CreateSymmetricKey(key);
- var bytes = WinRTCrypto.CryptographicEngine.Decrypt(symetricKey, data);
- return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
- }
- }
- }
Step 4
Create a new form in the common portable and set it as the main page in App.cs:
- using System;
- using Xamarin.Forms;
- namespace CryptoForms
- {
- public class MainPage : ContentPage
- {
- private Label label = null;
- private Button button = null;
- public MainPage()
- {
- button = new Button
- {
- Text = "Click me",
- };
- label = new Label
- {
- XAlign = TextAlignment.Center,
- Text = "Welcome to Xamarin Forms!"
- };
- button.Clicked += async (sender, e) =>
- {
- var data = "Cryptographic example";
- var pass = "MySecretKey";
- var contentPage = new ContentPage();
- var salt = Crypto.CreateSalt(16);
- await contentPage.DisplayAlert("Alert", "Encrypting String " + data + ", with salt " + BitConverter.ToString(salt), "OK");
- var bytes = Crypto.EncryptAes(data, pass, salt);
- await contentPage.DisplayAlert("Alert", "Encrypted, Now Decrypting", "OK");
- var str = Crypto.DecryptAes(bytes, pass, salt);
- await contentPage.DisplayAlert("Alert", "Decryted " + str, "OK");
- };
- this.Title = "Crypto Forms";
- // The root page of your application
- this.Content = new StackLayout
- {
- VerticalOptions = LayoutOptions.Center,
- Children =
- {
- label,
- button
- }
- };
- }
- }
- }
Step 5
Set CryptoForms.Driod as the Startup project and run. See the output in the Android Emulator below:
Step 6
Set CryptoForms.WinPhone as the Startup project and run. See the output in the Windows Phone emulator.
I have not modified any code in each platform-specific library. The advantage of a common portable is to have common code for all the platforms and Xamarin, on build, converts to platform-specifc code.
I have some problems in setting up the iOS environment since I don't have a Mac book. The alternative is to run the Mac OS in a virtual box to build and deploy the iOS app. iOS 64 bit must be installed but the virtual box doesn't support 64-bit guest OS when hyper-v is enabled in Windows features. Windows Phone runs only when hyper-v is enabled so testing is cumbersome with a couple of restarts for each Windows Phone and iOS.

Nuri YilmazPosted Oct 31, 2017, 5:28 AM
I'm really wondering how var salt = Crypto.CreateSalt(16); can salt data? :) I think something missed or wrong.
naga girishPosted May 31, 2017, 8:22 AM
Even i am facing the same issue... i cant use more than 32 bits... If i user more than 32 bits i get an odd error. {System.ArgumentException: Key length not 128/192/256 bits. ---> Java.Security.InvalidKeyException: Key length not 128/192/256 bits. ---> Java.Lang.IllegalArgumentException: Key length not 128/192/256 bits.
naga girishPosted May 18, 2017, 6:53 AM
I am getting this error during decrypt padding is invalid and cannot be removed... Can you please help.
Marcelo FernandesPosted Sep 12, 2016, 1:29 PM
Please, Could you give the code using async encrypt and decrypt ??? I?ll appreciate
Prasanna MuraliPosted Sep 5, 2016, 11:11 AM
Nice post......
Marcelo FernandesPosted Jun 28, 2016, 2:27 PM
Hi, first of all, thanks for the code...i have a question !! If i will use a webapi, i have to encripty on the client side and decripty on webapi...but, in your code, the PLC Crypto creates the Salt... whats the best way (more secure) to decripty on the Webapi and use the Salt ?
Claudio MaggioPosted Dec 29, 2015, 5:53 AM
Hi i have a problem i must encrypt using DesCbc algorithm but every try i do i recive the exception "DES Key too long - shoud be 8 bytes". Where is my error?
Raj BandiPosted Feb 17, 2015, 3:17 AM
Hi Sannket, You need to add PCLCrypto reference to your windows phone project i.e. Add PCLCrypto reference to common project and also to platform specific projects. Please add with nuget. Thanks, Raj
Sannket PatelPosted Feb 17, 2015, 2:51 AM
public static byte[] CreateSalt(uint lengthInBytes) { return WinRTCrypto.CryptographicBuffer.GenerateRandom(lengthInBytes); } All functions showing error as NotImplemented Exception. Please clarify , what PCLCrypto provide. Do we need to write code for each algorithms, Or we can use just directly ?
Vithal WadjePosted Dec 23, 2014, 9:41 PM
great start ,keep it up,thanks for sharing