Client side encryption for Azure Mobile Apps

IQrypt already integrates easily with Parse and Siaqodb via IQrypt plugins for Parse .NET SDK and Siaqodb and  today we’ll show how you can integrate IQrypt with Azure Mobile Apps and store data encrypted in Azure SQL Database. SQL Server 2016 and Azure SQL already offers Always Encrypted feature, however this is integrated only in ADO.NET driver  and is not available on Azure Mobile Client SDK which access the data via RESTful API.

Besides that, “Always Encrypted” offers only equivalent of DET(deterministic) and RND(randomized) encryption schemes, so you can only make equality/non equality queries using DET scheme.

IQrypt SDK offers many more schemes: RND(randomized), DET(deterministic), HMAC(keyed-hash), OPE(deterministic order preserving encryption), ROPE(randomized order preserving encryption) and BITMAP(client side bitmap index), empowering the server to execute many query types over encrypted data without decrypting it. A detailed description of those schemes that IQrypt SDK offers can be found here.

We will make a demo app called DoctorsRounds, it is a Windows Universal App supposed to be used by Doctors on a tablet or phone running Windows 10. Doctors will be able to visit patients in a hospital and fill information about those patients. We will encrypt patient data at the client side( on the device) before the data is sent to the cloud. At the end, the app will look like this:

doctorsrounds

So let’s start with the preparation, first we’ll need to setup our backend:

Creating a New Azure Mobile App

Inside of the Azure portal, simply select New -> Web + Mobile -> Mobile App, which is the starting point to configure your Azure Mobile App backend.

newapp

When selecting Mobile App in Azure, you will need to configure the service name (this is the URL where your backend  will live), configure your subscription, and set your resource group and plan.

appname

Add Data Connection

We can’t have a backend for our mobile apps without a database. Under the Data Connections section, select Add, and then configure a new SQL database , example bellow:

dataconnection

servercreation

Make sure that you keep Allow azure services to access server checked for your mobile app to allow services to properly connect to the database server. Also, be sure to keep your password in a secure place as you may need it in the future.

Click OK on all open windows and Azure will begin to create the database for us on the fly.

Adding ‘patients’ table

Under Mobile settings, look up for Easy Tables section, which enable us to easily set up and control the data coming to and from the client app. Select the Easy Tables section, and we’ll be prompted with a big blue warning asking us to configure Easy Tables/Easy APIs. Since we already setup the database, the only thing left to do is Initialize the app.

easytables1

 

After a few moments, the app will be fully initialized so we can add our first table of the database named patients. Easy Tables will automatically update and add the columns in the table dynamically based on the data we pass in. For this example, I’ll simply allow full anonymous access to the table, however it is possible to add authentication with Facebook, Twitter, Google, Microsoft, and other OAuth login providers.

easytables2

 

Our backend is fully functional, so let’s go to client now.

Client setup

We will define first the ‘Patient’ entity:

 

 

 
public class Patient
    {
        
        public string ObjectId { get; set; }
        public string PhotoThumbnail { get; set; }
        public string PhotoDetail { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Gender { get; set; }
        public string Location { get; set; }
        public string Building { get; set; }
        public string SSN { get; set; }
        public int Floor { get; set; }
        private DateTime _agenda_time;
        public DateTime AgendaTime 
        {
            get
            {
                return _agenda_time;
            }
            set
            {
                _agenda_time = value;
                String dtString = _agenda_time.Hour.ToString("00") + ":" + _agenda_time.Minute.ToString("00");
                AgendaHourMinute = dtString;
            }
        }

        public string AgendaHourMinute { get; set; }
        public string Treatment { get; set; }
        public string Status { get; set; }
        public string Doctor { get; set; }
        public string Version { get; set; }
        public PatientDetails PatientDetailsData { get; set; }
.......
}

PatientDetails contains other additional data (the definition can be found on Github repository).
The goal is that an entire Patient object is encrypted with RND encryption scheme and we will extract 3 tags that we want to search by:

  • SSN (Social Security Number) will be encrypted with DET so we can make equality queries
  • AgendaTime will be encrypted with OPE so we can make range queries
  • Building will be let as plain text since does not reveal sensitive info about the patient

To accomplish that, we will define the entity which will be stored in Azure SQL database as follow:

 

 

 
 [Microsoft.WindowsAzure.MobileServices.DataTable("patients")]
    public class AzurePatient
    {
        public string Id { get; set; }
        public string Patient { get; set; }
        public string SSN { get; set; }
        public string AgendaTime { get; set; }
        public string Building { get; set; }
    }

So, basically, within Patient property will be stored the entire Patient object encrypted with RND, within SSN will be store encrypted SSN value of the patient, similar for AgendaTime and Building properties.

Now we will create a repository interface; its implementors will manage AzurePatient objects and will be responsible with the communication with our Azure Mobile App backend:

 

 public interface IPatientRepository:IDisposable
 {
     Task InitRepo();
     Task<IList<Patient>> GetAll();
     Task<Patient> Get(string key);
     Task<IList<Patient>> GetByBuilding(string building, int limit);
     Task<IList<Patient>> GetByAgenda(DateTime agendatime, int limit);
     Task<Patient> GetBySSN(string sSN);
     Task Store(Patient item);
     Task StoreBatch(IList<Patient> items);
     Task Delete(Patient item); 
 
 }

Now let’s start implementing the methods of this interface. We would need to add references to Nuget packages:

Then compile IQrypt-UWP project from src/IQrypt/IQrypt-UWP and use IQrypt.dll from its /bin folder.

Then we will implement our repo, first we’ll do some initialization:

...
using Microsoft.WindowsAzure.MobileServices;
using IQrypt;

public class AzureMobileRepository : IPatientRepository
 {
    private MobileServiceClient mobileService;
    IEncryptor encryptorRND;
    IEncryptor encryptorDET;
    IEncryptor encryptorOPE;
    IMobileServiceTable<AzurePatient> table;
   public async Task InitRepo()
   {
     mobileService = new MobileServiceClient("https://iqryptdemo.azurewebsites.net");
     table = mobileService.GetTable<AzurePatient>();

     IQryptConfigurator.SetEncryptionChiper(Cipher.AES256, "mysuper_secret");
     encryptorRND = EncryptorFactory.GetEncryptor(EncryptionType.RND);
     encryptorDET = EncryptorFactory.GetEncryptor(EncryptionType.DET);
     encryptorOPE = EncryptorFactory.GetEncryptor(EncryptionType.OPE);
   }
.......

We have created above a reference to Azure ‘patients’ table, set IQrypt cipher + password(encryption key material) and create encryptors instances for the encryption schemes we need.
The app will check if we have any patients stored and if not, it will generate some patients with random info and the it will call StoreBatch method. So let’s implement this method:

 
 public async Task StoreBatch(IList<Patient> items)
        {
            foreach (Patient patient in items)
            {
                AzurePatient ap = new AzurePatient();

                ap.Patient = encryptorRND.Encrypt(patient);
                ap.AgendaTime = encryptorOPE.Encrypt(patient.AgendaTime);
                ap.SSN =encryptorDET.Encrypt( patient.SSN);
                ap.Building = patient.Building;
              
                ap.Id = Guid.NewGuid().ToString();
               
                await table.InsertAsync(ap);
            }
        }

So all data is encrypted with the respective encryption schemes before the object is sent to the cloud.

After calling this method, we can browse that data and we can see that the data is encrypted:

browsedata

Now let’s see how we will get the data back:

 
 public async Task<IList<Patient>> GetAll()
        {
          
            var allPatients=await table.ReadAsync();
            List<Patient> list = new List<Patient>();
            foreach (var azurePatient in allPatients)
            {
                Patient p = encryptorRND.Decrypt(azurePatient.Patient, typeof(Patient)) as Patient;
                p.ObjectId = azurePatient.Id;
                list.Add(p);
            }
            return list;
        }

So the only extra thing we had to do was to decrypt the Patient objects.
We will implement now the methods that executes queries, first GetBySSN:

 
 public async Task<Patient> GetBySSN(string SSN)
        {
            string ssnEncrypted = encryptorDET.Encrypt(SSN);
            var patients = await table.Where(p => p.SSN == ssnEncrypted).ToListAsync();
            if (patients.Count == 1)
            {
                Patient p = encryptorRND.Decrypt(patients[0].Patient, typeof(Patient)) as Patient;
                p.ObjectId = patients[0].Id;
                return p;
            }
            return null;
        }

First thing, we have encrypted the SSN we want to search by, then we pass the encrypted value to the server/cloud service and the server will execute the query and return the matched Patient object without decrypting anything.

Let’s see now how we can execute a range queries using OPE scheme:

  public async Task<IList<Patient>> GetByAgenda(DateTime agendatime, int limit)
        {
          
            string start =encryptorOPE.Encrypt(agendatime.Date);
            string end = encryptorOPE.Encrypt(agendatime.AddDays(1).Date);
            //load all patients with agenda time between start and end by OData query
            var allPatients = await table.ReadAsync("$filter=agendatime ge '" + start + "' and agendatime lt '" + end + "'&$top=" + limit);
            List<Patient> list = new List<Patient>();
            foreach (var azurePatient in allPatients)
            {
                Patient p = encryptorRND.Decrypt(azurePatient.Patient, typeof(Patient)) as Patient;
                p.ObjectId = azurePatient.Id;
                list.Add(p);
            }
            return list;
        }

As noticed, we run directly OData query because we cannot make LINQ query since the ‘start’ and ‘end’ are strings, but the server can execute queries using the operators ‘>=’  and ‘< ‘ even on string types.

Full source code of the app can be found on Github.  Take a look on the video bellow to see how to use the app:

 

Encrypt and stay safe!