HomeNikola Knezevic

In this article

Banner

Data Encryption with EF Core

28 May 2026
5 min

Special Thanks to Our Sponsors:

Sponsor Logo

EF Core is too slow? Discover how you can easily insert 14x faster (reducing saving time by 94%).

Boost your performance with our method within EF Core: Bulk Insert, update, delete and merge.

Thousands of satisfied customers have trusted our library since 2014.

👉 Learn more

Sponsor Newsletter

Protecting sensitive data is essential when working with personal or confidential data.

In .NET, cryptographic operations are commonly handled through the System.Security.Cryptography namespace, which provides secure implementations for encryption, hashing and key management.

Although Entity Framework Core does not provide built-in column encryption, it offers enough flexibility to integrate encryption directly into the persistence layer using features such as value converters.

In this blog post, we will implement transparent database field encryption in Entity Framework Core using AES and custom value converters.

Encryption

Encryption is the process of transforming readable data into an unreadable format that can only be restored using the correct key.

There are two main types of encryption:

  • Symmetric encryption uses the same secret key for encryption and decryption.
  • Asymmetric encryption uses a public and private key pair and is commonly used for secure communication.

To learn more about encryption, check out my blog post: AES Encryption in .NET

For many business applications, symmetric encryption is more than enough when protecting selected database columns such as emails, phone numbers, or personal information.

Encryption with AES

For this example, I made a small helper class:

csharp
public static class EncryptionHelper
{
    public static string Key { get; private set; }

    public static string Encrypt(string dataToEncrypt)
    {
        using var aes = Aes.Create();
        aes.Key = Encoding.UTF8.GetBytes(Key);
        aes.Mode = CipherMode.ECB;
        aes.Padding = PaddingMode.PKCS7;

        var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

        using var memoryStream = new MemoryStream();
        using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
        using (var streamWriter = new StreamWriter(cryptoStream))
        {
            streamWriter.Write(dataToEncrypt);
        }

        return Convert.ToBase64String(memoryStream.ToArray());
    }

    public static string Decrypt(string dataToDecrypt)
    {
        using var aes = Aes.Create();
        aes.Key = Encoding.UTF8.GetBytes(Key);
        aes.Mode = CipherMode.ECB;
        aes.Padding = PaddingMode.PKCS7;

        var descriptor = aes.CreateDecryptor(aes.Key, aes.IV);

        var buffer = Convert.FromBase64String(dataToDecrypt);
        using var memoryStream = new MemoryStream(buffer);
        using var cryptoStream = new CryptoStream(memoryStream, descriptor, CryptoStreamMode.Read);
        using var streamReader = new StreamReader(cryptoStream);

        return streamReader.ReadToEnd();
    }

    public static void SetEncryptionKey(string key) => Key = key;
}

The symmetric key is configured once during application startup and reused for both encryption and decryption operations. Encrypted values are stored in the database as Base64 encoded strings.

NOTE: For production-grade systems, you would typically avoid ECB mode and instead use CBC or GCM with a unique IV per value. Proper key derivation and secure key storage are also strongly recommended.

Encryption converter

A Value Converter in EF Core is responsible for transforming property values when reading from or writing to the database.

If you want to learn more about value converters and how they work internally, check out my detailed article on EF Core value converters: Value Conversions in EF Core

In this example, we will create a custom converter that will automatically encrypt values before they are persisted and decrypt them when they are materialized from the database:

csharp
public class EncryptionConvertor : ValueConverter<string, string>
{
    public EncryptionConvertor(ConverterMappingHints mappingHints) : base(
        value => EncryptionHelper.Encrypt(value),
        value => EncryptionHelper.Decrypt(value),
        mappingHints)
    {
    }

    public EncryptionConvertor() : base(
        value => EncryptionHelper.Encrypt(value),
        value => EncryptionHelper.Decrypt(value))
    {
    }
}

This keeps encryption completely transparent to the rest of the application.

EF Core Configuration

The final step is configuring EF Core to use the custom converter for selected properties.

For this example, we will use a simple Customer entity:

csharp
public sealed class Customer
{
    public Guid Id { get; set; }
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Customer(string email, string firstName, string lastName)
    {
        Id = Guid.NewGuid();
        Email = email;
        FirstName = firstName;
        LastName = lastName;
    }
}

Encryption is applied at the mapping layer using HasConversion<EncryptionConvertor>:.

csharp
public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
    public void Configure(EntityTypeBuilder<Customer> builder)
    {
        builder.ToTable(TableNames.Customers);

        builder.HasKey(c => c.Id);

        builder.Property(c => c.Id).IsRequired();

        builder.Property(c => c.Email)
            .IsRequired()
            .HasConversion<EncryptionConvertor>();

        builder.Property(c => c.FirstName)
            .IsRequired()
            .HasConversion<EncryptionConvertor>();

        builder.Property(c => c.LastName)
            .IsRequired()
            .HasConversion<EncryptionConvertor>();
    }
}

Conclusion

By combining AES encryption with EF Core value converters, we can transparently encrypt sensitive values before they are stored in the database and automatically decrypt them when they are read.

This approach keeps the encryption logic centralized, reusable and isolated from the rest of the application code.

If you want to check out examples I created, you can find the source code here:

Source Code

I hope you enjoyed it, subscribe and get a notification when a new blog is up!

Subscribe

Stay tuned for valuable insights every Thursday morning.