Skip to content

Commit 0beb736

Browse files
authored
Merge pull request #45 from Eastrall/wip/v4
Version 4.0.0
2 parents de814ed + b56a363 commit 0beb736

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1309
-2150
lines changed

.editorconfig

Lines changed: 0 additions & 39 deletions
This file was deleted.

.github/workflows/build.yml

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,22 @@ on:
99
jobs:
1010
build-library:
1111
runs-on: ubuntu-latest
12+
1213
steps:
13-
- uses: actions/checkout@v2
14+
- name: Checkout repository
15+
uses: actions/checkout@v3
1416

15-
- name: Setup .NET
16-
uses: actions/setup-dotnet@v1
17+
- name: Setup .NET Core
18+
uses: actions/setup-dotnet@v3
1719
with:
18-
dotnet-version: 6.0.x
20+
dotnet-version: |
21+
3.1.x
22+
5.0.x
23+
6.0.x
24+
7.0.x
25+
26+
- name: Display .NET version
27+
run: dotnet --version
1928

2029
- name: Restore dependencies
2130
run: dotnet restore
@@ -24,4 +33,13 @@ jobs:
2433
run: dotnet build EntityFrameworkCore.DataEncryption.sln --configuration Release -f net6.0 --no-restore
2534

2635
- name: Run unit tests
27-
run: dotnet test EntityFrameworkCore.DataEncryption.sln --configuration Release /p:CollectCoverage=true /p:Exclude="[xunit*]*" /p:CoverletOutputFormat=opencover /p:CoverletOutput="../TestResults/TestResults.xml" /maxcpucount:1 -f net6.0 --no-build --verbosity normal
36+
run: dotnet test --configuration Release --collect:"XPlat Code Coverage" --settings ./test/EntityFrameworkCore.DataEncryption.Test/runsettings.xml
37+
38+
- name: Copy coverage results
39+
run: cp ./test/EntityFrameworkCore.DataEncryption.Test/TestResults/**/*.xml ./test/EntityFrameworkCore.DataEncryption.Test/TestResults/
40+
41+
- name: Upload code coverage
42+
uses: codecov/codecov-action@v3
43+
with:
44+
files: ./test/EntityFrameworkCore.DataEncryption.Test/TestResults/coverage.opencover.xml
45+
fail_ci_if_error: true

EntityFrameworkCore.DataEncryption.sln

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.30804.86
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.3.32901.215
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3EC10767-1816-46B2-A78E-9856071CCFDB}"
77
EndProject
@@ -22,17 +22,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{64C3
2222
EndProject
2323
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AesSample", "samples\AesSample\AesSample.csproj", "{8AA1E576-4016-4623-96C8-90330F05F9A8}"
2424
EndProject
25-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".azure", ".azure", "{073FEA06-67CF-47F8-8CE4-2B153A7D8443}"
25+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{EEF46CDC-C438-48FC-BEF7-83AEE26C63F7}"
2626
EndProject
27-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pipelines", "pipelines", "{68558245-F605-413F-A1D9-A4F60D489D68}"
27+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{4F549FEF-C57B-4A34-A2C7-8A632762DF85}"
2828
ProjectSection(SolutionItems) = preProject
29-
.azure\pipelines\azure-pipelines.yml = .azure\pipelines\azure-pipelines.yml
30-
EndProjectSection
31-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5EE4E8BE-6B15-49DB-A4A8-D2CD63D5E90C}"
32-
ProjectSection(SolutionItems) = preProject
33-
.editorconfig = .editorconfig
29+
.github\workflows\build.yml = .github\workflows\build.yml
3430
EndProjectSection
3531
EndProject
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AesSample.Fluent", "samples\AesSample.Fluent\AesSample.Fluent.csproj", "{CF04DE64-713F-4ED3-9C14-B7C11D22454C}"
33+
EndProject
3634
Global
3735
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3836
Debug|Any CPU = Debug|Any CPU
@@ -51,6 +49,10 @@ Global
5149
{8AA1E576-4016-4623-96C8-90330F05F9A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
5250
{8AA1E576-4016-4623-96C8-90330F05F9A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
5351
{8AA1E576-4016-4623-96C8-90330F05F9A8}.Release|Any CPU.Build.0 = Release|Any CPU
52+
{CF04DE64-713F-4ED3-9C14-B7C11D22454C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53+
{CF04DE64-713F-4ED3-9C14-B7C11D22454C}.Debug|Any CPU.Build.0 = Debug|Any CPU
54+
{CF04DE64-713F-4ED3-9C14-B7C11D22454C}.Release|Any CPU.ActiveCfg = Release|Any CPU
55+
{CF04DE64-713F-4ED3-9C14-B7C11D22454C}.Release|Any CPU.Build.0 = Release|Any CPU
5456
EndGlobalSection
5557
GlobalSection(SolutionProperties) = preSolution
5658
HideSolutionNode = FALSE
@@ -59,8 +61,9 @@ Global
5961
{D037F8D0-E606-4C5A-8669-DB6AAE7B056B} = {3EC10767-1816-46B2-A78E-9856071CCFDB}
6062
{5E023B6A-0B47-4EC2-90B9-2DF998E58ADB} = {E4089551-AF4E-41B3-A6F8-2501A3BE0E0C}
6163
{8AA1E576-4016-4623-96C8-90330F05F9A8} = {64C3D7D1-67B8-4070-AE67-C71B761535CC}
62-
{073FEA06-67CF-47F8-8CE4-2B153A7D8443} = {3A8D800E-77BD-44EF-82DB-C672281ECAAA}
63-
{68558245-F605-413F-A1D9-A4F60D489D68} = {073FEA06-67CF-47F8-8CE4-2B153A7D8443}
64+
{EEF46CDC-C438-48FC-BEF7-83AEE26C63F7} = {3A8D800E-77BD-44EF-82DB-C672281ECAAA}
65+
{4F549FEF-C57B-4A34-A2C7-8A632762DF85} = {EEF46CDC-C438-48FC-BEF7-83AEE26C63F7}
66+
{CF04DE64-713F-4ED3-9C14-B7C11D22454C} = {64C3D7D1-67B8-4070-AE67-C71B761535CC}
6467
EndGlobalSection
6568
GlobalSection(ExtensibilityGlobals) = postSolution
6669
SolutionGuid = {4997BAE9-29BF-4D79-AE5E-5605E7A0F049}

README.md

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
[![.NET](https://github.com/Eastrall/EntityFrameworkCore.DataEncryption/actions/workflows/build.yml/badge.svg)](https://github.com/Eastrall/EntityFrameworkCore.DataEncryption/actions/workflows/build.yml)
44
[![codecov](https://codecov.io/gh/Eastrall/EntityFrameworkCore.DataEncryption/branch/master/graph/badge.svg)](https://codecov.io/gh/Eastrall/EntityFrameworkCore.DataEncryption)
55
[![Nuget](https://img.shields.io/nuget/v/EntityFrameworkCore.DataEncryption.svg)](https://www.nuget.org/packages/EntityFrameworkCore.DataEncryption)
6+
[![Nuget Downloads](https://img.shields.io/nuget/dt/EntityFrameworkCore.DataEncryption)](https://www.nuget.org/packages/EntityFrameworkCore.DataEncryption)
67

78
`EntityFrameworkCore.DataEncryption` is a [Microsoft Entity Framework Core](https://github.com/aspnet/EntityFrameworkCore) extension to add support of encrypted fields using built-in or custom encryption providers.
89

910
## Disclaimer
1011

11-
This library has been developed initialy for a personal project of mine. It provides a simple way to encrypt column data.
12+
<h4 align="center">:warning: This project is **not** affiliated with Microsoft. :warning:</h4><br>
1213

13-
I **do not** take responsability if you use this in a production environment and loose your encryption key.
14+
This library has been developed initialy for a personal project of mine which suits my use case. It provides a simple way to encrypt column data.
15+
16+
I **do not** take responsability if you use/deploy this in a production environment and loose your encryption key or corrupt your data.
1417

1518
## How to install
1619

@@ -19,17 +22,29 @@ Install the package from [NuGet](https://www.nuget.org/) or from the `Package Ma
1922
PM> Install-Package EntityFrameworkCore.DataEncryption
2023
```
2124

22-
## How to use
25+
## Supported types
2326

24-
To use `EntityFrameworkCore.DataEncryption`, you will need to decorate your `string` properties of your entities with the `[Encrypted]` attribute and enable the encryption on the `ModelBuilder`.
27+
| Type | Default storage type |
28+
|------|----------------------|
29+
| `string` | Base64 string |
30+
| `byte[]` | BINARY |
2531

26-
To enable the encryption correctly, you will need to use an **encryption provider**, there is a list of the available providers:
32+
## Built-in providers
2733

2834
| Name | Class | Extra |
2935
|------|-------|-------|
30-
| [AES](https://docs.microsoft.com/en-US/dotnet/api/system.security.cryptography.aes?view=netcore-2.2) | [AesProvider](https://github.com/Eastrall/EntityFrameworkCore.DataEncryption/blob/master/src/EntityFrameworkCore.DataEncryption/Providers/AesProvider.cs) | Can use a 128bits, 192bits or 256bits key |
36+
| [AES](https://learn.microsoft.com/en-US/dotnet/api/system.security.cryptography.aes?view=net-6.0) | [AesProvider](https://github.com/Eastrall/EntityFrameworkCore.DataEncryption/blob/main/src/EntityFrameworkCore.DataEncryption/Providers/AesProvider.cs) | Can use a 128bits, 192bits or 256bits key |
37+
38+
## How to use
39+
40+
`EntityFrameworkCore.DataEncryption` supports 2 differents initialization methods:
41+
* Attribute
42+
* Fluent configuration
3143

32-
### Example with `AesProvider`
44+
Depending on the initialization method you will use, you will need to decorate your `string` or `byte[]` properties of your entities with the `[Encrypted]` attribute or use the fluent `IsEncrypted()` method in your model configuration process.
45+
To use an encryption provider on your EF Core model, and enable the encryption on the `ModelBuilder`.
46+
47+
### Example with `AesProvider` and attribute
3348

3449
```csharp
3550
public class UserEntity
@@ -58,34 +73,72 @@ public class DatabaseContext : DbContext
5873
public DatabaseContext(DbContextOptions options)
5974
: base(options)
6075
{
61-
this._provider = new AesProvider(this._encryptionKey, this._encryptionIV);
76+
_provider = new AesProvider(this._encryptionKey, this._encryptionIV);
6277
}
6378

6479
protected override void OnModelCreating(ModelBuilder modelBuilder)
6580
{
66-
modelBuilder.UseEncryption(this._provider);
81+
modelBuilder.UseEncryption(_provider);
6782
}
6883
}
6984
```
70-
The code bellow creates a new `AesEncryption` provider and gives it to the current model. It will encrypt every `string` fields of your model that has the `[Encrypted]` attribute when saving changes to database. As for the decrypt process, it will be done when reading the `DbSet<T>` of your `DbContext`.
85+
The code bellow creates a new [`AesProvider`](https://github.com/Eastrall/EntityFrameworkCore.DataEncryption/blob/main/src/EntityFrameworkCore.DataEncryption/Providers/AesProvider.cs) and gives it to the current model. It will encrypt every `string` fields of your model that has the `[Encrypted]` attribute when saving changes to database. As for the decrypt process, it will be done when reading the `DbSet<T>` of your `DbContext`.
7186

72-
## Create an encryption provider
87+
### Example with `AesProvider` and fluent configuration
88+
89+
```csharp
90+
public class UserEntity
91+
{
92+
public int Id { get; set; }
93+
public string Username { get; set; }
94+
public string Password { get; set; }
95+
public int Age { get; set; }
96+
}
7397

74-
> :warning: This section is outdated and doesn't work for V3.0.0 and will be updated soon.
98+
public class DatabaseContext : DbContext
99+
{
100+
// Get key and IV from a Base64String or any other ways.
101+
// You can generate a key and IV using "AesProvider.GenerateKey()"
102+
private readonly byte[] _encryptionKey = ...;
103+
private readonly byte[] _encryptionIV = ...;
104+
private readonly IEncryptionProvider _provider;
105+
106+
public DbSet<UserEntity> Users { get; set; }
107+
108+
public DatabaseContext(DbContextOptions options)
109+
: base(options)
110+
{
111+
_provider = new AesProvider(this._encryptionKey, this._encryptionIV);
112+
}
113+
114+
protected override void OnModelCreating(ModelBuilder modelBuilder)
115+
{
116+
// Entities builder *MUST* be called before UseEncryption().
117+
var userEntityBuilder = modelBuilder.Entity<UserEntity>();
118+
119+
userEntityBuilder.Property(x => x.Username).IsRequired().IsEncrypted();
120+
userEntityBuilder.Property(x => x.Password).IsRequired().IsEncrypted();
121+
122+
modelBuilder.UseEncryption(_provider);
123+
}
124+
}
125+
```
126+
127+
## Create an encryption provider
75128

76129
`EntityFrameworkCore.DataEncryption` gives the possibility to create your own encryption providers. To do so, create a new class and make it inherit from `IEncryptionProvider`. You will need to implement the `Encrypt(string)` and `Decrypt(string)` methods.
77130

78131
```csharp
79132
public class MyCustomEncryptionProvider : IEncryptionProvider
80133
{
81-
public string Encrypt(string dataToEncrypt)
134+
public byte[] Encrypt(byte[] input)
82135
{
83-
// Encrypt data and return as Base64 string
136+
// Encrypt the given input and return the encrypted data as a byte[].
84137
}
85138

86-
public string Decrypt(string dataToDecrypt)
139+
public byte[] Decrypt(byte[] input)
87140
{
88-
// Decrypt a Base64 string to plain string
141+
// Decrypt the given input and return the decrypted data as a byte[].
89142
}
90143
}
91144
```
@@ -99,12 +152,12 @@ public class DatabaseContext : DbContext
99152
public DatabaseContext(DbContextOptions options)
100153
: base(options)
101154
{
102-
this._provider = new MyCustomEncryptionProvider();
155+
_provider = new MyCustomEncryptionProvider();
103156
}
104157

105158
protected override void OnModelCreating(ModelBuilder modelBuilder)
106159
{
107-
modelBuilder.UseEncryption(this._provider);
160+
modelBuilder.UseEncryption(_provider);
108161
}
109162
}
110163
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<LangVersion>10</LangVersion>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.10" />
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.10" />
12+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.10" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\src\EntityFrameworkCore.DataEncryption\EntityFrameworkCore.DataEncryption.csproj" />
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.DataEncryption;
3+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
4+
using System.ComponentModel.DataAnnotations;
5+
6+
namespace AesSample.Fluent;
7+
8+
public class DatabaseContext : DbContext
9+
{
10+
private readonly IEncryptionProvider _encryptionProvider;
11+
12+
public DbSet<UserEntity> Users { get; set; }
13+
14+
public DatabaseContext(DbContextOptions<DatabaseContext> options, IEncryptionProvider encryptionProvider)
15+
: base(options)
16+
{
17+
_encryptionProvider = encryptionProvider;
18+
}
19+
20+
protected override void OnModelCreating(ModelBuilder modelBuilder)
21+
{
22+
EntityTypeBuilder<UserEntity> userEntityBuilder = modelBuilder.Entity<UserEntity>();
23+
24+
userEntityBuilder.HasKey(x => x.Id);
25+
userEntityBuilder.Property(x => x.Id).IsRequired().ValueGeneratedOnAdd();
26+
userEntityBuilder.Property(x => x.FirstName).IsRequired();
27+
userEntityBuilder.Property(x => x.LastName).IsRequired();
28+
userEntityBuilder.Property(x => x.Email).IsRequired().IsEncrypted();
29+
userEntityBuilder.Property(x => x.Notes).IsRequired().HasColumnType("BLOB").IsEncrypted(StorageFormat.Binary);
30+
userEntityBuilder.Property(x => x.EncryptedData).IsRequired().IsEncrypted();
31+
userEntityBuilder.Property(x => x.EncryptedDataAsString).IsRequired().HasColumnType("TEXT").IsEncrypted(StorageFormat.Base64);
32+
33+
if (_encryptionProvider is not null)
34+
{
35+
modelBuilder.UseEncryption(_encryptionProvider);
36+
}
37+
38+
base.OnModelCreating(modelBuilder);
39+
}
40+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace AesSample.Fluent;
4+
5+
public class EncryptedDatabaseContext : DatabaseContext
6+
{
7+
public EncryptedDatabaseContext(DbContextOptions<DatabaseContext> options)
8+
: base(options, null)
9+
{
10+
}
11+
}

0 commit comments

Comments
 (0)