Search code examples
c#encryptioncryptographygetter-setter

Design pattern for encrypting/decrypting object properties in Get/Set


I am trying to find a good design pattern that will allow me to store a users private information as encrypted cipher text yet make the encryption/decryption seamless to the user of the object.

For example ... lets say I have a Patient object and a property on the object is some private information such as Social Security Number (SSN). I want to store this in the database as an encrypted value yet allow application code to get/set the SSN using syntax such as ...

// Getting the unencrypted SSN
var currentSSN = selectedPatient.SSN;

// Setting the unencrypted SSN, but will be encrypted in Setter
selectedPatient.SSN = "555-55-5555";

I tried placing the encryption/decryption in the getter and setter as such ...

public string SSN
{
  get 
  {
    return MyEncryptionClass.Decrypt(this.SSN);
  }
  set
  {
    value =  MyEncryptionClass.Encrypt(value);
  }
}

NOTE: Assume the Key and Initialization Vector are both handled by the Encrypt/Decrypt methods. I wanted to focus on the Get/Set portion.

The problem is I find that the SSN is stored as plain text in the database record even though I have the Encrypt method in the Setter. I can confirm by debugging that the Encrypt routine is in fact returning proper cipher text, yet it does not seem to be stored in the database record as such. My thinking is that the Get/Set is somewhat circular. That by setting the value I am calling the decrypt method so what gets stored in the record is in fact decrypted.

Is there a pattern that people have found that works that allows this encryption/decryption to be seamless to the consumer of the object. I want to avoid them from having to manually call the encrypt/decrypt methods.

EDIT - I am using Entity Framework v6


Solution

  • A simple pattern could be the following:

    // this property will be persisted in the database, but can't be modified from outside
    public string SSN { get; private set; }
    
    // the attribute will make sure this doesn't get mapped to the db
    // this property uses the other property as a backing field with proper conversions
    [NotMapped]
    public string SSNDecrypted
    {
      get 
      {
        return MyEncryptionClass.Decrypt(this.SSN);
      }
      set
      {
        this.SSN =  MyEncryptionClass.Encrypt(value);
      }
    }