Skip to content

Commit 55fa814

Browse files
authored
Merge pull request #12 from Eastrall/feature/fixIV
Dynamic IV per field
2 parents 40a32c6 + ffd6f91 commit 55fa814

File tree

11 files changed

+121
-101
lines changed

11 files changed

+121
-101
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: csharp
22
mono: none
3-
dotnet: 3.0.100
3+
dotnet: 3.1.403
44

55
env:
66
global:
@@ -18,8 +18,8 @@ jobs:
1818
name: ".NET Core 3 (Mac: OS X)"
1919

2020
script:
21-
- dotnet build ./src/$PROJECT_NAME/$PROJECT_NAME.csproj -c Release -f netstandard2.1
22-
- dotnet test ./test/$PROJECT_NAME.Test/$PROJECT_NAME.Test.csproj -c Release -f netcoreapp3.0 /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[xunit*]*"
21+
- dotnet build ./src/$PROJECT_NAME/$PROJECT_NAME.csproj -c Release
22+
- dotnet test ./test/$PROJECT_NAME.Test/$PROJECT_NAME.Test.csproj -c Release /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[xunit*]*"
2323

2424
after_script:
2525
- bash <(curl -s https://codecov.io/bash)

src/EntityFrameworkCore.DataEncryption/EntityFrameworkCore.DataEncryption.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
4+
<TargetFrameworks>netstandard2.0</TargetFrameworks>
55
<AssemblyName>EntityFrameworkCore.DataEncryption</AssemblyName>
66
<RootNamespace>Microsoft.EntityFrameworkCore.DataEncryption</RootNamespace>
7-
<Version>1.1.0</Version>
7+
<Version>2.0.0</Version>
88
<Authors>Filipe GOMES PEIXOTO</Authors>
99
<PackageId>EntityFrameworkCore.DataEncryption</PackageId>
1010
<PackageProjectUrl>https://github.com/Eastrall/EntityFrameworkCore.DataEncryption</PackageProjectUrl>
@@ -13,17 +13,17 @@
1313
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
1414
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1515
<PackageTags>entity-framework-core, extensions, dotnet-core, dotnet, encryption, fluent-api</PackageTags>
16-
<LangVersion>7.3</LangVersion>
16+
<LangVersion>8.0</LangVersion>
1717
<PackageIcon>icon.png</PackageIcon>
18-
<Copyright>Filipe GOMES PEIXOTO © 2019</Copyright>
18+
<Copyright>Filipe GOMES PEIXOTO © 2019 - 2020</Copyright>
1919
<Description>A plugin for Microsoft.EntityFrameworkCore to add support of encrypted fields using built-in or custom encryption providers.</Description>
2020
<PackageLicenseFile>LICENSE</PackageLicenseFile>
21-
<PackageReleaseNotes>- Add support for Entity Framework Core 3</PackageReleaseNotes>
21+
<PackageReleaseNotes>- Remove initializationVector parameter from `AesProvider` constructor.
22+
- Apply unique IV for each row.</PackageReleaseNotes>
2223
</PropertyGroup>
2324

2425
<ItemGroup>
25-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
26-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" Condition="'$(TargetFramework)' == 'netstandard2.1'" />
26+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
2727
</ItemGroup>
2828

2929
<ItemGroup>

src/EntityFrameworkCore.DataEncryption/ModelBuilderExtensions.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using System;
2-
using Microsoft.EntityFrameworkCore.DataEncryption.Internal;
1+
using Microsoft.EntityFrameworkCore.DataEncryption.Internal;
32
using Microsoft.EntityFrameworkCore.Metadata;
3+
using System;
44
using System.ComponentModel.DataAnnotations;
55
using System.Linq;
66

@@ -19,7 +19,9 @@ public static class ModelBuilderExtensions
1919
public static void UseEncryption(this ModelBuilder modelBuilder, IEncryptionProvider encryptionProvider)
2020
{
2121
if (encryptionProvider == null)
22-
return;
22+
{
23+
throw new ArgumentNullException(nameof(encryptionProvider), "Cannot initialize encryption with a null provider.");
24+
}
2325

2426
var encryptionConverter = new EncryptionConverter(encryptionProvider);
2527

@@ -31,7 +33,9 @@ public static void UseEncryption(this ModelBuilder modelBuilder, IEncryptionProv
3133
{
3234
object[] attributes = property.PropertyInfo.GetCustomAttributes(typeof(EncryptedAttribute), false);
3335
if (attributes.Any())
36+
{
3437
property.SetValueConverter(encryptionConverter);
38+
}
3539
}
3640
}
3741
}

src/EntityFrameworkCore.DataEncryption/Providers/AesKeyInfo.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,29 @@ namespace Microsoft.EntityFrameworkCore.DataEncryption.Providers
2424
/// <param name="iv">AES initialization vector.</param>
2525
internal AesKeyInfo(byte[] key, byte[] iv)
2626
{
27-
this.Key = key;
28-
this.IV = iv;
27+
Key = key;
28+
IV = iv;
2929
}
3030

3131
/// <summary>
3232
/// Determines whether the current <see cref="AesKeyInfo"/> is equal to another <see cref="AesKeyInfo"/>.
3333
/// </summary>
3434
/// <param name="other"></param>
3535
/// <returns></returns>
36-
public bool Equals(AesKeyInfo other) => (this.Key, this.IV) == (other.Key, other.IV);
36+
public bool Equals(AesKeyInfo other) => (Key, IV) == (other.Key, other.IV);
3737

3838
/// <summary>
3939
/// Determines whether the current object is equal to another object of the same type.
4040
/// </summary>
4141
/// <param name="obj"></param>
4242
/// <returns></returns>
43-
public override bool Equals(object obj) => (obj is AesKeyInfo keyInfo) && this.Equals(keyInfo);
43+
public override bool Equals(object obj) => (obj is AesKeyInfo keyInfo) && Equals(keyInfo);
4444

4545
/// <summary>
4646
/// Calculates the hash code for the current <see cref="AesKeyInfo"/> instance.
4747
/// </summary>
4848
/// <returns></returns>
49-
public override int GetHashCode() => (this.Key, this.IV).GetHashCode();
49+
public override int GetHashCode() => (Key, IV).GetHashCode();
5050

5151
/// <summary>
5252
/// Determines whether the current <see cref="AesKeyInfo"/> is equal to another <see cref="AesKeyInfo"/>.

src/EntityFrameworkCore.DataEncryption/Providers/AesProvider.cs

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,36 @@ namespace Microsoft.EntityFrameworkCore.DataEncryption.Providers
1111
public class AesProvider : IEncryptionProvider
1212
{
1313
private const int AesBlockSize = 128;
14+
private const int InitializationVectorSize = 16;
15+
1416
private readonly byte[] _key;
15-
private readonly byte[] _initializationVector;
1617
private readonly CipherMode _mode;
1718
private readonly PaddingMode _padding;
1819

20+
/// <summary>
21+
/// Creates a new <see cref="AesProvider"/> instance used to perform symetric encryption and decryption on strings.
22+
/// </summary>
23+
/// <param name="key">AES key used for the symetric encryption.</param>
24+
/// <param name="mode">Mode for operation used in the symetric encryption.</param>
25+
/// <param name="padding">Padding mode used in the symetric encryption.</param>
26+
public AesProvider(byte[] key, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
27+
{
28+
_key = key;
29+
_mode = mode;
30+
_padding = padding;
31+
}
32+
1933
/// <summary>
2034
/// Creates a new <see cref="AesProvider"/> instance used to perform symetric encryption and decryption on strings.
2135
/// </summary>
2236
/// <param name="key">AES key used for the symetric encryption.</param>
2337
/// <param name="initializationVector">AES Initialization Vector used for the symetric encryption.</param>
2438
/// <param name="mode">Mode for operation used in the symetric encryption.</param>
2539
/// <param name="padding">Padding mode used in the symetric encryption.</param>
40+
[Obsolete("This constructor has been deprecated and will be removed in future versions. Please use the AesProvider(byte[], CipherMode, PaddingMode) constructor instead.")]
2641
public AesProvider(byte[] key, byte[] initializationVector, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
42+
: this(key, mode, padding)
2743
{
28-
this._key = key;
29-
this._initializationVector = initializationVector;
30-
this._mode = mode;
31-
this._padding = padding;
3244
}
3345

3446
/// <summary>
@@ -41,14 +53,25 @@ public string Encrypt(string dataToEncrypt)
4153
byte[] input = Encoding.UTF8.GetBytes(dataToEncrypt);
4254
byte[] encrypted = null;
4355

44-
using (var aes = this.CreateNewAesEncryptor())
56+
using (AesCryptoServiceProvider cryptoServiceProvider = CreateCryptographyProvider())
4557
{
46-
using (var memoryStream = new MemoryStream())
58+
cryptoServiceProvider.GenerateIV();
59+
60+
byte[] initializationVector = cryptoServiceProvider.IV;
61+
62+
using (ICryptoTransform encryptor = cryptoServiceProvider.CreateEncryptor(_key, initializationVector))
4763
{
48-
using (var crypto = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
49-
crypto.Write(input, 0, input.Length);
64+
using (var memoryStream = new MemoryStream())
65+
{
66+
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
67+
{
68+
memoryStream.Write(initializationVector, 0, initializationVector.Length);
69+
cryptoStream.Write(input, 0, input.Length);
70+
cryptoStream.FlushFinalBlock();
71+
}
5072

51-
encrypted = memoryStream.ToArray();
73+
encrypted = memoryStream.ToArray();
74+
}
5275
}
5376
}
5477

@@ -63,33 +86,36 @@ public string Encrypt(string dataToEncrypt)
6386
public string Decrypt(string dataToDecrypt)
6487
{
6588
byte[] input = Convert.FromBase64String(dataToDecrypt);
89+
6690
string decrypted = string.Empty;
6791

68-
using (var aes = this.CreateNewAesEncryptor())
92+
using (var memoryStream = new MemoryStream(input))
6993
{
70-
using (var memoryStream = new MemoryStream(input))
71-
using (var crypto = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
72-
using (var sr = new StreamReader(crypto))
73-
decrypted = sr.ReadToEnd().Trim('\0');
94+
var initializationVector = new byte[InitializationVectorSize];
95+
96+
memoryStream.Read(initializationVector, 0, initializationVector.Length);
97+
98+
using AesCryptoServiceProvider cryptoServiceProvider = CreateCryptographyProvider();
99+
using ICryptoTransform cryptoTransform = cryptoServiceProvider.CreateDecryptor(_key, initializationVector);
100+
using var crypto = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read);
101+
using var reader = new StreamReader(crypto);
102+
103+
decrypted = reader.ReadToEnd().Trim('\0');
74104
}
75105

76106
return decrypted;
77107
}
78108

79-
/// <summary>
80-
/// Creates a new <see cref="Aes"/> instance with the current configuration.
81-
/// </summary>
82-
/// <returns></returns>
83-
private Aes CreateNewAesEncryptor()
109+
private AesCryptoServiceProvider CreateCryptographyProvider()
84110
{
85-
var aes = Aes.Create();
86-
87-
aes.Mode = this._mode;
88-
aes.Padding = this._padding;
89-
aes.Key = this._key;
90-
aes.IV = this._initializationVector;
91-
92-
return aes;
111+
return new AesCryptoServiceProvider
112+
{
113+
BlockSize = AesBlockSize,
114+
Mode = _mode,
115+
Padding = _padding,
116+
Key = _key,
117+
KeySize = _key.Length * 8
118+
};
93119
}
94120

95121
/// <summary>

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ public sealed class AuthorEntity
2525

2626
public AuthorEntity(string firstName, string lastName, int age)
2727
{
28-
this.FirstName = firstName;
29-
this.LastName = lastName;
30-
this.Age = age;
31-
this.Books = new List<BookEntity>();
28+
FirstName = firstName;
29+
LastName = lastName;
30+
Age = age;
31+
Books = new List<BookEntity>();
3232
}
3333
}
3434
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ public sealed class BookEntity
2424

2525
public BookEntity(string name, int numberOfPages)
2626
{
27-
this.Name = name;
28-
this.NumberOfPages = numberOfPages;
27+
Name = name;
28+
NumberOfPages = numberOfPages;
2929
}
3030
}
3131
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ public DatabaseContext(DbContextOptions options)
1515
public DatabaseContext(DbContextOptions options, IEncryptionProvider encryptionProvider = null)
1616
: base(options)
1717
{
18-
this._encryptionProvider = encryptionProvider;
18+
_encryptionProvider = encryptionProvider;
1919
}
2020
protected override void OnModelCreating(ModelBuilder modelBuilder)
21-
=> modelBuilder.UseEncryption(this._encryptionProvider);
21+
{
22+
modelBuilder.UseEncryption(_encryptionProvider);
23+
}
2224
}
2325
}

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ public sealed class DatabaseContextFactory : IDisposable
1717
/// </summary>
1818
public DatabaseContextFactory()
1919
{
20-
this._connection = new SqliteConnection(DatabaseConnectionString);
21-
this._connection.Open();
22-
23-
using (var dbContext = new DatabaseContext(this.CreateOptions<DatabaseContext>()))
24-
dbContext.Database.EnsureCreated();
20+
_connection = new SqliteConnection(DatabaseConnectionString);
21+
_connection.Open();
2522
}
2623

2724
/// <summary>
@@ -32,10 +29,11 @@ public DatabaseContextFactory()
3229
/// <returns></returns>
3330
public TContext CreateContext<TContext>(IEncryptionProvider provider = null) where TContext : DbContext
3431
{
35-
if (provider == null)
36-
return Activator.CreateInstance(typeof(TContext), this.CreateOptions<TContext>()) as TContext;
32+
var context = Activator.CreateInstance(typeof(TContext), CreateOptions<TContext>(), provider) as TContext;
33+
34+
context.Database.EnsureCreated();
3735

38-
return Activator.CreateInstance(typeof(TContext), this.CreateOptions<TContext>(), provider) as TContext;
36+
return context;
3937
}
4038

4139
/// <summary>
@@ -51,9 +49,9 @@ private DbContextOptions<TContext> CreateOptions<TContext>() where TContext : Db
5149
/// </summary>
5250
public void Dispose()
5351
{
54-
if (this._connection != null)
52+
if (_connection != null)
5553
{
56-
this._connection.Dispose();
54+
_connection.Dispose();
5755
}
5856
}
5957
}

test/EntityFrameworkCore.DataEncryption.Test/EntityFrameworkCore.DataEncryption.Test.csproj

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,22 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>netcoreapp2.2;netcoreapp3.0</TargetFrameworks>
5-
4+
<TargetFramework>netcoreapp3.0</TargetFramework>
65
<IsPackable>false</IsPackable>
7-
86
<AssemblyName>Microsoft.EntityFrameworkCore.Encryption.Test</AssemblyName>
9-
107
<RootNamespace>Microsoft.EntityFrameworkCore.Encryption.Test</RootNamespace>
118
</PropertyGroup>
129

1310
<ItemGroup>
14-
<PackageReference Include="coverlet.msbuild" Version="2.7.0">
11+
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
1512
<PrivateAssets>all</PrivateAssets>
1613
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
1714
</PackageReference>
18-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" Condition="'$(TargetFramework)' == 'netcoreapp3.0'" />
19-
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.0.0" Condition="'$(TargetFramework)' == 'netcoreapp3.0'" />
20-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0" Condition="'$(TargetFramework)' == 'netcoreapp3.0'" />
21-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" Condition="'$(TargetFramework)' == 'netcoreapp2.2'" />
22-
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.1.0" Condition="'$(TargetFramework)' == 'netcoreapp2.2'" />
23-
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" Condition="'$(TargetFramework)' == 'netcoreapp2.2'" />
24-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
15+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
16+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.0" />
17+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
2518
<PackageReference Include="xunit" Version="2.4.1" />
26-
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
19+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
2720
<PrivateAssets>all</PrivateAssets>
2821
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
2922
</PackageReference>

0 commit comments

Comments
 (0)