How do I encrypt data in Entity Framework Code First?

azure c# ef-code-first encryption entity-framework

Question

I've been trying and failing to figure out a good approach to encrypting SQL data with the Entity Framework Code First. I must preface this with that I am hosting in Azure and do not have access to native SQL encryption.

Taking a page from SecurEntity, I have fully implemented an approach that utilizes SaveChanges and ObjectMaterialized to handle the encrypting/decrypting of the entities, but in testing I have found this has been far too unreliable to use.

Here is a sample of some of the implementation:

public override int SaveChanges()
{
    var pendingEntities = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager
        .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
        .Where(en => !en.IsRelationship).ToList();

    foreach (var entry in pendingEntities) //Encrypt all pending changes
        EncryptEntity(entry.Entity);

    int result = base.SaveChanges();

    foreach (var entry in pendingEntities) //Decrypt updated entities for continued use
        DecryptEntity(entry.Entity);

    return result;
}

void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{
    DecryptEntity(e.Entity);
}

I've seen other posts that manually encrypt/decrypt via secondary properties, like so:

public Value { get; set; }

[NotMapped]
public DecryptedValue
{
    get { return Decrypt(this.Value); }
    set { this.Value = Encrypt(value); }
}

This will most definitely work, but I find this approach to be... less than ideal. When using this approach, all the developers have to wade through all the encrypted properties to find which ones they can use.

The most ideal solution would be for me to be able to override the getting/setting of each value at the data-access level. Is there a way to do this? If not, how can I implement data encryption with Entity Framework - Code First so that it will be easy to maintain and work with?

1
13
4/8/2014 5:28:39 PM

Accepted Answer

I have good news. The instability I was experiencing with the SaveChanges/ObjectMaterialized approach was due to the fact that DetectChanges() isn't called until the DbContext actually performs the save.

I was able to fix this by calling DetectChanges() before I pulled the Added/Modified records from the ObjectStateManager. This cleared up any object state oddities that were causing inconsistent encryption behavior.

The resulting code being:

public override int SaveChanges()
{
    var contextAdapter = ((IObjectContextAdapter)this);

    contextAdapter.ObjectContext.DetectChanges();

    var pendingEntities = contextAdapter.ObjectContext.ObjectStateManager
        .GetObjectStateEntries(EntityState.Added | EntityState.Modified)
        .Where(en => !en.IsRelationship).ToList();

    foreach (var entry in pendingEntities) //Encrypt all pending changes
        EncryptEntity(entry.Entity);

    int result = base.SaveChanges();

    foreach (var entry in pendingEntities) //Decrypt updated entities for continued use
        DecryptEntity(entry.Entity);

    return result;
}

EDIT - Added a sample DataContext to see my end-to-end solution for encrypting all entities. Note: You don't have to use a custom attribute for encrypting properties. Source

11
11/21/2014 4:31:13 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow