DKNet

DKNet.EfCore.Encryption

Encrypt and decrypt EF Core string columns through value converters for .NET developers.

✨ Why use it?

🚀 Quick Start

Use a .NET 10 console project. Install the packages, then replace Program.cs with the example.

dotnet new console -f net10.0 -n EfCoreDemo
cd EfCoreDemo
dotnet add package DKNet.EfCore.Encryption
dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 10.0.12
using System.Security.Cryptography;
using DKNet.EfCore.Encryption;
using DKNet.EfCore.Encryption.Attributes;
using DKNet.EfCore.Encryption.Encryption;
using DKNet.EfCore.Encryption.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

using var connection = new Microsoft.Data.Sqlite.SqliteConnection("Data Source=:memory:");
connection.Open();
var services = new ServiceCollection();
services.AddEfCoreEncryption<DemoKey>();
services.AddDbContext<DemoDb>(o => o.UseSqlite(connection));
using var provider = services.BuildServiceProvider();
using var scope = provider.CreateScope();
await using var db = scope.ServiceProvider.GetRequiredService<DemoDb>();
await db.Database.EnsureCreatedAsync();
db.Add(new Customer { Secret = "demo-value" });
await db.SaveChangesAsync();
db.ChangeTracker.Clear();
Console.WriteLine((await db.Customers.SingleAsync()).Secret); // demo-value
using var command = connection.CreateCommand();
command.CommandText = "SELECT Secret FROM Customers";
Console.WriteLine((string)command.ExecuteScalar()! != "demo-value"); // True

public sealed class DemoKey : IEncryptionKeyProvider
{
    private readonly byte[] _key = RandomNumberGenerator.GetBytes(32);
    public byte[] GetKey(Type entityType) => _key;
}
public sealed class DemoDb(DbContextOptions<DemoDb> options, IEncryptionKeyProvider keys) : DbContext(options)
{
    public DbSet<Customer> Customers => Set<Customer>();
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.UseColumnEncryption(keys);
    }
}
public sealed class Customer
{
    public int Id { get; set; }
    [Encrypted]
    public string? Secret { get; set; }
}

Run with dotnet run.

🏗️ Architecture

OnModelCreating uses the key provider to attach AES-GCM ColumnEncryptionConverter instances to marked strings, so EF writes ciphertext and materializes plaintext.

Only EF Core is referenced by this package. AddEfCoreEncryption registers a singleton key provider; converters and their provider capture keys when the EF model is built. There is no SaveChanges hook or key-vault client.

🔄 How it works

UseColumnEncryption selects marked string properties, rejects primary or foreign key columns, obtains entity keys and installs converters that encrypt writes and decrypt reads.

The demo uses an ephemeral key only for its in-memory database. Persisted databases need a stable protected key across restarts. Null and empty strings pass through, while malformed or unauthenticated ciphertext throws.

🧩 Features