Skip to content

Commit 3a699ba

Browse files
committed
Fix encryption converters storage formats
1 parent 96e169b commit 3a699ba

File tree

7 files changed

+83
-32
lines changed

7 files changed

+83
-32
lines changed

README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
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

@@ -21,13 +22,13 @@ PM> Install-Package EntityFrameworkCore.DataEncryption
2122

2223
## How to use
2324

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`.
25+
To use `EntityFrameworkCore.DataEncryption`, you will need to decorate your `string` or `byte[]` properties of your entities with the `[Encrypted]` attribute and enable the encryption on the `ModelBuilder`.
2526

2627
To enable the encryption correctly, you will need to use an **encryption provider**, there is a list of the available providers:
2728

2829
| Name | Class | Extra |
2930
|------|-------|-------|
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 |
31+
| [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 |
3132

3233
### Example with `AesProvider`
3334

@@ -71,21 +72,19 @@ The code bellow creates a new `AesEncryption` provider and gives it to the curre
7172

7273
## Create an encryption provider
7374

74-
> :warning: This section is outdated and doesn't work for V3.0.0 and will be updated soon.
75-
7675
`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.
7776

7877
```csharp
7978
public class MyCustomEncryptionProvider : IEncryptionProvider
8079
{
81-
public string Encrypt(string dataToEncrypt)
80+
public byte[] Encrypt(byte[] input)
8281
{
83-
// Encrypt data and return as Base64 string
82+
// Encrypt the given input and return the encrypted data as a byte[].
8483
}
8584

86-
public string Decrypt(string dataToDecrypt)
85+
public byte[] Decrypt(byte[] input)
8786
{
88-
// Decrypt a Base64 string to plain string
87+
// Decrypt the given input and return the decrypted data as a byte[].
8988
}
9089
}
9190
```

samples/AesSample/Program.cs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ static void Main()
2727
FirstName = "John",
2828
LastName = "Doe",
2929
Email = "[email protected]",
30-
//Password = BuildPassword(),
30+
EncryptedData = new byte[2] { 1, 2 },
31+
EncryptedDataAsString = new byte[2] { 3, 4 }
3132
};
3233

3334
context.Users.Add(user);
@@ -39,19 +40,4 @@ static void Main()
3940

4041
Console.WriteLine($"User: {user.FirstName} {user.LastName} - {user.Email}");
4142
}
42-
43-
static SecureString BuildPassword()
44-
{
45-
SecureString result = new();
46-
result.AppendChar('L');
47-
result.AppendChar('e');
48-
result.AppendChar('t');
49-
result.AppendChar('M');
50-
result.AppendChar('e');
51-
result.AppendChar('I');
52-
result.AppendChar('n');
53-
result.AppendChar('!');
54-
result.MakeReadOnly();
55-
return result;
56-
}
5743
}

samples/AesSample/UserEntity.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.ComponentModel.DataAnnotations;
33
using System.ComponentModel.DataAnnotations.Schema;
4-
using System.Security;
54

65
namespace AesSample;
76

@@ -21,5 +20,12 @@ public class UserEntity
2120
[Encrypted]
2221
public string Email { get; set; }
2322

24-
//public SecureString Password { get; set; }
23+
[Required]
24+
[Encrypted]
25+
public byte[] EncryptedData { get; set; }
26+
27+
[Required]
28+
[Encrypted(StorageFormat.Base64)]
29+
[Column(TypeName = "VARCHAR(MAX)")]
30+
public byte[] EncryptedDataAsString { get; set; }
2531
}

src/EntityFrameworkCore.DataEncryption/ModelBuilderExtensions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,22 @@ private static ValueConverter GetValueConverter(Type propertyType, IEncryptionPr
6565
{
6666
return storageFormat switch
6767
{
68-
StorageFormat.Default or StorageFormat.Base64 => new EncryptionConverter<string, string>(encryptionProvider, storageFormat),
69-
StorageFormat.Binary => new EncryptionConverter<string, byte[]>(encryptionProvider, storageFormat),
68+
StorageFormat.Default or StorageFormat.Base64 => new EncryptionConverter<string, string>(encryptionProvider, StorageFormat.Base64),
69+
StorageFormat.Binary => new EncryptionConverter<string, byte[]>(encryptionProvider, StorageFormat.Binary),
7070
_ => throw new NotImplementedException()
7171
};
7272
}
7373
else if (propertyType == typeof(byte[]))
7474
{
7575
return storageFormat switch
7676
{
77-
StorageFormat.Default or StorageFormat.Binary => new EncryptionConverter<byte[], byte[]>(encryptionProvider, storageFormat),
78-
StorageFormat.Base64 => new EncryptionConverter<byte[], string>(encryptionProvider, storageFormat),
77+
StorageFormat.Default or StorageFormat.Binary => new EncryptionConverter<byte[], byte[]>(encryptionProvider, StorageFormat.Binary),
78+
StorageFormat.Base64 => new EncryptionConverter<byte[], string>(encryptionProvider, StorageFormat.Base64),
7979
_ => throw new NotImplementedException()
8080
};
8181
}
8282

83-
return null;
83+
throw new NotImplementedException($"Type {propertyType.Name} does not support encryption.");
8484
}
8585

8686
private static IEnumerable<EncryptedProperty> GetEntityEncryptedProperties(IMutableEntityType entity)

test/EntityFrameworkCore.DataEncryption.Test/Context/BookEntity.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ public sealed class BookEntity
2525
[ForeignKey(nameof(AuthorId))]
2626
public AuthorEntity Author { get; set; }
2727

28+
[Encrypted(StorageFormat.Base64)]
29+
[Column(TypeName = "TEXT")]
30+
public byte[] Content { get; set; }
31+
2832
public BookEntity(string name, int numberOfPages)
2933
{
3034
Name = name;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using Microsoft.EntityFrameworkCore.DataEncryption;
2+
using Microsoft.EntityFrameworkCore.DataEncryption.Providers;
3+
using Microsoft.EntityFrameworkCore.DataEncryption.Test.Context;
4+
using System;
5+
using System.ComponentModel.DataAnnotations;
6+
using System.ComponentModel.DataAnnotations.Schema;
7+
using Xunit;
8+
9+
namespace Microsoft.EntityFrameworkCore.Encryption.Test;
10+
11+
public class ModelBuilderExtensionsTest
12+
{
13+
private class InvalidPropertyEntity
14+
{
15+
[Key]
16+
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
17+
public int Id { get; set; }
18+
19+
[Encrypted]
20+
public string Name { get; set; }
21+
22+
[Encrypted]
23+
public int Age { get; set; }
24+
}
25+
26+
private class InvalidPropertyDbContext : DbContext
27+
{
28+
private readonly IEncryptionProvider _encryptionProvider;
29+
30+
public DbSet<InvalidPropertyEntity> InvalidEntities { get; set; }
31+
32+
public InvalidPropertyDbContext(DbContextOptions options)
33+
: base(options)
34+
{ }
35+
36+
public InvalidPropertyDbContext(DbContextOptions options, IEncryptionProvider encryptionProvider = null)
37+
: base(options)
38+
{
39+
_encryptionProvider = encryptionProvider;
40+
}
41+
protected override void OnModelCreating(ModelBuilder modelBuilder)
42+
{
43+
modelBuilder.UseEncryption(_encryptionProvider);
44+
}
45+
}
46+
47+
[Fact]
48+
public void UseEncryptionWithUnsupportedTypeTest()
49+
{
50+
AesKeyInfo encryptionKeyInfo = AesProvider.GenerateKey(AesKeySize.AES256Bits);
51+
var provider = new AesProvider(encryptionKeyInfo.Key, encryptionKeyInfo.IV);
52+
53+
using var contextFactory = new DatabaseContextFactory();
54+
55+
Assert.Throws<NotImplementedException>(() => contextFactory.CreateContext<InvalidPropertyDbContext>(provider));
56+
}
57+
}

test/EntityFrameworkCore.DataEncryption.Test/Providers/AesProviderTest.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ private static void ExecuteAesEncryptionTest<TContext>(AesKeySize aesKeyType) wh
138138
var provider = new AesProvider(encryptionKeyInfo.Key, encryptionKeyInfo.IV, CipherMode.CBC, PaddingMode.Zeros);
139139
var author = new AuthorEntity("John", "Doe", 42)
140140
{
141-
//Password = DataHelper.RandomSecureString(10),
142141
Books = new List<BookEntity>
143142
{
144143
new("Lorem Ipsum", 300),

0 commit comments

Comments
 (0)