Encrypting data the easy way using Crypteron
Story of my life: I'm in the middle of some logistics-project for a hospital or a moving company or a security firm or (God-forbid) the government. Specs have been finalized for months, the business model is implemented in EF, we have a test environment filled with test users and test data, and I'm just about to feel happy about how smoothly the project is going. Too good to be true, right? Right.
One day I arrive at work and my manager tells me that there is a little modification in the requirements: we have to store some data encrypted. Not a big deal — just the user's e-mail (and since the username is sometimes also the e-mail, that too), every personal data (birthdate, address etc.), and the patient's file (in case this is a hospital administration portal). And I'm f....
Admitting defeat
I have to say, I haven't come accross any good solution that I would be confident to apply (same as with my soft delete problem; maybe I should tackle this one as well.) You might be in a lucky position of using SQL Azure as your database, in which case you can use the transparent encryption feature (but I've never tried it with EF, I'm not sure if they work well together). Or if you use SQL Server 2016+, you can use the always encrypted feature, but it has its limitations But since a lot of people still think that the cloud is only the CIA's plan (or the aliens') to steal all our data, you cannot go in the cloud; you have to use on-prem SQL Server. And for some reason, big insurance companies and multinational companies and the government (God-forbib) tend to cling to a version of SQL Server that's so old, it doesn't event have a version number. And again, you're f....
This is the point where I usually give up, acknowledge that I've been defeated and do what I always encourage software engineers not to: I create a static CryptoHelper with two Encrypt() and Decrypt() methods and do a 'Find all reference' and call the Encrypt() and Decrypt() methods before saving to the database and before returning data to the views. And I try to rationalize that every other solution that I could come up with would have a lot repercussions at this point in the development.
Crypteron
During one of my battles, just before admitting defeat I came accross a service called Crypteron. It's premise is promising:
Data security is hard. Crypteron makes it easy. Supercharge your backend applications with turn-key encryption and key management.
So I've decided to try it. And to be honest, I'm not sure how much I can write about it, because it just works :) First, you have to log in to the Crypteron-portal and register your application. This will generate a key that's used for the enryption:
Then you have to add the key to the config file:
<crypteronConfig>
<myCrypteronAccount appSecret="EiAgImGf9izE3KG9IB7tOwzYBt9LVVT4IIPLY1k2wwcHORjcEw==" />
</crypteronConfig>
Then, you have to dedicate your model classes with a special attribute from Crypteron's nuget package:
public class Player
{
public int PersonId { get; set; }
public int Age{ get; set; }
[Secure]
public string Address{ get; set; }
}
And modify your dbcontext:
public class CrypteronContext : DbContext
{
public DbSet<Player> Players { get; set; }
public CrypteronContext()
{
Crypteron.CipherDb.Session.Create(this);
}
}
And that's it! Encryption is handled inside the application, on-the-fly. Your data never touches Crpyteron's servers, neither in plain nor in encrypted form. And of course, they have the necessary badges from the neccessary audit companies, so you can easily shut legal up :)
Extra features that I like
A simple, but useful one: you have the option to disable your encryption keys on Crpyteron's portal, in case you suspect a data-breach. Nice.
Search encrypted data. Of course this is not possible — or at least not yet. I'm told by people who are a lot smarter than me that it is coming (they call it homomorphic encryption), but it's still 30-40 years from being actually usable in vivo.
But crypteron has a feature for this as well: you can just indicate in the attribute that the field is searchable, and that's it.
public class Player
{
public int PersonId { get; set; }
public int Age{ get; set; }
[Secure(Mode=Mode.Searchable)]
public string Address{ get; set; }
}
How does this work under the hood? Here's an excerpt from the Crypteron-blog (if you are interested, read the whole thing):
Behind the scenes, Crypteron is generating an in-place, cryptographically secure, distributed search index. This happens as each piece of data is added and is constructed on-the-fly on a per searchable column/field basis. The distributed search index uses a HMAC-SHA256 primitive...
It's impressive. But what I'm most impressed with is the ready-to-be-used nature of the service and the supporting libraries.
I only tried the community edition, but based on the descriptions, the advanced versions have some very useful features (rotating the encryption keys or defining access control rules).
Drawbacks
One drawback though: I don't really like the attribute solution. If I have to dedicate my model classes with a Crypteron-specific attribute, I have to add a dependency to those DLL-s. But I don't really want to. I like to keep my model assembly clean, as few dependencies as possible (not even Entity Framework itself) and just POCO classes and some domain specific data annotations. In my opinion this makes the code a lot more reusable. I'm looking forward to a solution where I can use the EntityTypeConfiguration class and maybe an extension method on it to configure crpytography like this:
public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
public PersonEntityTypeConfigration()
{
this.Property(p=>p.Email).IsSecure(Mode.Searchable);
}
}
Conclusion
All in all, I'm looking forward to using this service in one of my next projects. I'm happy to see that the cryptography-sector is also embracing what a 'service' really means: it's ready-to-be-used, it's easy-to-use, you don't have to be a crypto-genius to start using it and you have all the support that you need (both in documentation, in samples and in actual customer support) in case you decide to introduce it into you application.