Eastrall / EntityFrameworkCore.DataEncryption

A plugin for Microsoft.EntityFrameworkCore to add support of encrypted fields using built-in or custom encryption providers.
MIT License
326 stars 54 forks source link

Newbie to AES Encryption question .... #3

Closed BrettStrongEH closed 4 years ago

BrettStrongEH commented 4 years ago

Hi There,

Just giving your library a whirl (thanks for this contribution by the way :) ) ... everything ins place, however i am now just trying to figure out how to correctly generate a valid AES Key and IV value.

I tried using an online AES Key Gen utility (there are many out there), I generated one 256 bit base64 string for the and another for the IV value .. however when I attempt to save some data to an EF Entity property which stipulates the [Encrypted] attribute I get the following error:

CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm.

Obviously the process I followed to generate the key and IV value is incorrect.

For refs sake I am loading these base64 values from environment variables when testing locally, but the goal is to load them from a protected key store or parameter store like AWS SSM for actual production environment.

Any advice here ?

eL-Prova commented 4 years ago

Hi Brett,

Have you take a look at the sources? The AesProvider has a method GenerateKey. https://github.com/Eastrall/EntityFrameworkCore.DataEncryption/blob/master/src/EntityFrameworkCore.DataEncryption/Providers/AesProvider.cs

We are using this in our application with docker and stores the IV and and key in the protected store. When starting your application you can read this from your environment.

Eastrall commented 4 years ago

Hi @BrettStrongEH, thank you for using EntityFrameworkCore.DataEncryption!

@eL-Prova is correct. The AesProvider class has a GenerateKey() method that generates an encryption key and IV for you. It will return you a AesKeyInfo structure which contains the Key and the IV.

There is a sample snippet

AesKeyInfo keyInfo = AesProvider.GenerateKey(AesKeySize.AES256Bits);

string keyAsString = Convert.ToBase64String(keyInfo.Key);
string ivAsString = Convert.ToBase64String(keyInfo.IV);

// TODO: store keyAsString and ivAsString in files or a secure storage.

The AesKeySize has the following options:

You can choose the one you want.

Hope it helps. 😄

BrettStrongEH commented 4 years ago

Thankyou both @eL-Prova and @Eastrall for the quick responses and info here. It really is much appreciated.

Just to clarify on the approach I should be using when generating the key in this way …

My understanding is that I only need to generate this Key and IV value once, store it somewhere as a static value, and from that point onwards, I can only ever use these static values to encrypt and decrypt values into in my DB (i.e. by using them to initialize the EntityFrameworkCore.DataEncrytpion -> AesProvider in the constructor of the DBContext).

So that said, would an adequate strategy be to create a separate console app utility that references AesProvider to generate Key and IV, so that I can then store these values in environment variables or say the AWS SSM store (which is where I was planning on storing it for production purposes).

Or would you just detect if any keys exist on first application run, and then store somewhere for ongoing use as part of the app initialization process … ?

Sorry just trying to understand where abouts in the process you generate the keys, store and then subsequently use for lifetime of app.

Thanks again for the advice guys.

eL-Prova commented 4 years ago

No you dont want to create it when it is not found. Especially when working with containers. When spinup 2 different containers will create two IV and keys for same database. You need to be in the lead. So the option to create a IV and Key from the source is enough, how to cosume it in your sources it the responsibility of the developer.

I have less experience with AWS but I expect you cant write to a secret store from your application (I hope). For docker it isnt possible so when spinup the container you give the IV and Key as parameter for the secret store.

Eastrall commented 4 years ago

What I recommend is creating a simple console application, that will generate a key and an IV converted in a base64 string and then save the values somewhere. (File, secret storage, etc...)

In every applications that consumes the database, you will need this key and IV to encrypt and decrypt the database's encrypted content. If you use another key and IV, well, you simply can't decrypt correctly the database data.

Imagine you have a locked door and you have two keys. If you don't have the correct key, you will not be able to open it. Same goes for the database encryption system.

Once you have saved your keys somewhere, you can load it when your program starts and then pass it to your DbContext.

class Program
{
    private static void Main()
    {
        // Create the encryption provider
        IEncryptionProvider encryptionProvider = CreateEncryptionProvider();

        // Create the DbContext with the encryption provider
        var dbContext = new MyDbContext(dbContextOptions, encryptionProvider);
    }

    private static AesProvider CreateEncryptionProvider()
    {
        // Load the key and the IV from somewhere: files, secret storage
        byte[] encryptionKey = LoadKeyFromSomewhere();
        byte[] iv = LoadIVFromSomewhere();

        // Return a new AesProvider with the loaded encryption key and iv
        return new AesProvider(encryptionKey, iv);
    }
}

class MyDbContext : DbContext
{
    private readonly IEncryptionProvider _encryptionProvider;

    public MyDbContext(DbContextOptions options, IEncryptionProvider encryptionProvider = null)
        : base()
    {
        this._encryptionProvider = encryptionProvider;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.UseEncryption(this._encryptionProvider);
    }
}

Hope it helps.

BrettStrongEH commented 4 years ago

Thanks for the awesome advice and example @Eastrall.

Totally get it now.

Eastrall commented 4 years ago

I'm glad it helped. Feel free to close the issue if it's solved.