diff --git a/EncryptColumnTest/Context/ExampleDbContext.cs b/EncryptColumnTest/Context/ExampleDbContext.cs new file mode 100644 index 0000000..5c142b2 --- /dev/null +++ b/EncryptColumnTest/Context/ExampleDbContext.cs @@ -0,0 +1,33 @@ +using EncryptColumnTest.Models; +using EntityFrameworkCore.EncryptColumn.Interfaces; +using EntityFrameworkCore.EncryptColumn.Util; +using Microsoft.EntityFrameworkCore; +using EntityFrameworkCore.EncryptColumn.Extension; + +namespace EncryptColumnTest.Context; + +public class ExampleDbContext:DbContext + { + private readonly IEncryptionProvider _provider; + public ExampleDbContext() + { + this._provider = new GenerateEncryptionProvider("example_encrypt_key_must be 32 b"); + } + + public DbSet Users { get; set; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=EncryptColumnTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.UseEncryption(this._provider); + //modelBuilder.HasDefaultSchema("dbo"); + //modelBuilder.Entity(entity => + //{ + // entity.ToTable("Users"); + // entity.HasKey(u => u.ID).HasName("PK_User_Id"); + // entity.Property(p => p.ID).HasColumnType("GUID").IsRequired().ValueGeneratedOnAdd(); + //}); + } + } + diff --git a/EncryptColumnTest/EncryptColumnTest.csproj b/EncryptColumnTest/EncryptColumnTest.csproj new file mode 100644 index 0000000..eabd25e --- /dev/null +++ b/EncryptColumnTest/EncryptColumnTest.csproj @@ -0,0 +1,58 @@ + + + + net6.0;net7.0;net8.0 + enable + + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/EncryptColumnTest/Migrations/20220314125216_initial.Designer.cs b/EncryptColumnTest/Migrations/20220314125216_initial.Designer.cs new file mode 100644 index 0000000..23c2b9e --- /dev/null +++ b/EncryptColumnTest/Migrations/20220314125216_initial.Designer.cs @@ -0,0 +1,56 @@ +// +using System; +using EncryptColumnTest.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace EncryptColumnTest.Migrations +{ + [DbContext(typeof(ExampleDbContext))] + [Migration("20220314125216_initial")] + partial class initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("EncryptColumnTest.Models.User", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Firstname") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IdentityNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Lastname") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("ID"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/EncryptColumnTest/Migrations/20220314125216_initial.cs b/EncryptColumnTest/Migrations/20220314125216_initial.cs new file mode 100644 index 0000000..e2dc60e --- /dev/null +++ b/EncryptColumnTest/Migrations/20220314125216_initial.cs @@ -0,0 +1,34 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EncryptColumnTest.Migrations +{ + public partial class initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Users", + columns: table => new + { + ID = table.Column(type: "uniqueidentifier", nullable: false), + Firstname = table.Column(type: "nvarchar(max)", nullable: false), + Lastname = table.Column(type: "nvarchar(max)", nullable: false), + EmailAddress = table.Column(type: "nvarchar(max)", nullable: false), + IdentityNumber = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Users", x => x.ID); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Users"); + } + } +} diff --git a/EncryptColumnTest/Migrations/ExampleDbContextModelSnapshot.cs b/EncryptColumnTest/Migrations/ExampleDbContextModelSnapshot.cs new file mode 100644 index 0000000..51b9fa0 --- /dev/null +++ b/EncryptColumnTest/Migrations/ExampleDbContextModelSnapshot.cs @@ -0,0 +1,54 @@ +// +using System; +using EncryptColumnTest.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace EncryptColumnTest.Migrations +{ + [DbContext(typeof(ExampleDbContext))] + partial class ExampleDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + + modelBuilder.Entity("EncryptColumnTest.Models.User", b => + { + b.Property("ID") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EmailAddress") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Firstname") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IdentityNumber") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Lastname") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("ID"); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/EncryptColumnTest/Models/User.cs b/EncryptColumnTest/Models/User.cs new file mode 100644 index 0000000..a8e5bec --- /dev/null +++ b/EncryptColumnTest/Models/User.cs @@ -0,0 +1,23 @@ +using EntityFrameworkCore.EncryptColumn.Attribute; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EncryptColumnTest.Models; + +public class User + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public Guid? ID { get; set; } + public string? Firstname { get; set; } + public string? Lastname { get; set; } + [EncryptColumn] + public string? EmailAddress { get; set; } + [EncryptColumn] + public string? IdentityNumber { get; set; } + } diff --git a/EncryptColumnTest/UnitTest1.cs b/EncryptColumnTest/UnitTest1.cs new file mode 100644 index 0000000..36d2386 --- /dev/null +++ b/EncryptColumnTest/UnitTest1.cs @@ -0,0 +1,95 @@ +using EncryptColumnTest.Context; +using EncryptColumnTest.Models; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Linq; + +namespace EncryptColumnTest; +[TestClass] +public class UnitTest1 + { + private static ExampleDbContext testContext=new(); + private User testUser = new User + { + Firstname = "Emre", + Lastname = "Kizildas", + EmailAddress = "kizildas@icloud.com", + IdentityNumber = "12345678901" + }; + + public UnitTest1() + { + //testContext=new(); + } + + //[ClassInitialize()] + //public static void Initialize() + // { + // testContext.Users.RemoveRange(testContext.Users); // clear the database. + // } + + [TestMethod] + public void AddRecord() + { + try + { + testContext.Users.Add(testUser); + testContext.SaveChanges(); + } + catch(Exception Ex) + { + Assert.Fail($"Exception thrown on {nameof(AddRecord)}: {Ex.Message}"); + } + } + + [TestMethod] + public void ReadRecordByName() + { + try + { + var user = testContext.Users.FirstOrDefault(u => u.Firstname == testUser.Firstname); + Assert.IsNotNull(user); + Assert.IsNotNull(user.Firstname); + Assert.AreEqual(testUser.Firstname, user.Firstname); + Assert.AreEqual(testUser.IdentityNumber, user.IdentityNumber); + Assert.AreEqual(testUser.EmailAddress, user.EmailAddress); + } + catch(Exception Ex) + { + Assert.Fail($"Exception thrown on {nameof(ReadRecordByName)}: {Ex.Message}"); + } + } + + [TestMethod] + public void ReadRecordByIdentityNumber() + { + try + { + var user = testContext.Users.FirstOrDefault(u => u.IdentityNumber == testUser.IdentityNumber); + Assert.IsNotNull(user); + Assert.IsNotNull(user.Firstname); + Assert.AreEqual("Emre", user.Firstname); + Assert.AreEqual("12345678901", user.IdentityNumber); + Assert.AreEqual("kizildas@icloud.com", user.EmailAddress); + } + catch(Exception Ex) + { + Assert.Fail($"Exception thrown on {nameof(ReadRecordByName)}: {Ex.Message}"); + } + } + + [TestMethod] + public void AddAnotherRecord() + { + try + { + User newUser = new User { EmailAddress="jdubois31@outlook.com", Firstname="John", Lastname="Dubois", IdentityNumber="299792458" }; + testContext.Users.Add(newUser); + testContext.SaveChanges(); + } + catch (Exception Ex) + { + Assert.Fail($"Exception thrown on {nameof(AddAnotherRecord)}: {Ex.Message}"); + } + } + } \ No newline at end of file diff --git a/EntityFramework.Core.EncryptDBColumn/EntityFrameworkCore.EncryptColumn.csproj b/EntityFramework.Core.EncryptDBColumn/EntityFrameworkCore.EncryptColumn.csproj index b4103d5..c445a44 100644 --- a/EntityFramework.Core.EncryptDBColumn/EntityFrameworkCore.EncryptColumn.csproj +++ b/EntityFramework.Core.EncryptDBColumn/EntityFrameworkCore.EncryptColumn.csproj @@ -1,19 +1,22 @@  - net6.0 + net6.0;net7.0;net8.0 true - 6.0.8 + 6.1.1 Emre Kizildas - https://github.com/emrekizildas/EntityFrameworkCore.EncryptColumn/raw/main/EntityFramework.Core.EncryptDBColumn/icon.png + icon.png en-US Emre Kizildas https://github.com/emrekizildas/EntityFrameworkCore.EncryptColumn Encrypt & Decrypt your databases columns using EntityFramework Core. entityframeworkcore, encryption, encrypt sql, encrypt column, entityframework EntityFrameworkCore.EncryptColumn - Use EncryptColumn attribute and your database columns encrtypted. Automatic encrypt and decrypt your columns. + Use the EncryptColumn attribute on your database columns to encrtypt them. Automaticly encrypt and decrypt your columns. EntityFrameworkCore.EncryptColumn + 6.1.1 + True + Copyright © $(Authors) 2023 @@ -24,10 +27,8 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + diff --git a/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs b/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs index 31cc1f3..f578f6d 100644 --- a/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs +++ b/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs @@ -5,76 +5,76 @@ using EntityFrameworkCore.EncryptColumn.Interfaces; namespace EntityFrameworkCore.EncryptColumn.Util -{ - public class GenerateEncryptionProvider : IEncryptionProvider - { + { + public class GenerateEncryptionProvider:IEncryptionProvider + { private readonly string key; public GenerateEncryptionProvider(string key) { this.key = key; } - public string Encrypt(string dataToEncrypt) - { - if (string.IsNullOrEmpty(key)) - throw new ArgumentNullException("EncryptionKey", "Please initialize your encryption key."); + public string Encrypt(string dataToEncrypt) + { + if(string.IsNullOrEmpty(key)) + throw new ArgumentNullException("EncryptionKey", "Please initialize your encryption key."); - if (string.IsNullOrEmpty(dataToEncrypt)) - return string.Empty; - - byte[] iv = new byte[16]; - byte[] array; + if(string.IsNullOrEmpty(dataToEncrypt)) + return string.Empty; - using (Aes aes = Aes.Create()) - { - aes.Key = Encoding.UTF8.GetBytes(key); - aes.IV = iv; + byte[] iv = new byte[16]; + byte[] array; - ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV); - using (MemoryStream memoryStream = new MemoryStream()) - { - using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write)) - { - using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream)) - { - streamWriter.Write(dataToEncrypt); - } - array = memoryStream.ToArray(); - } - } - } - string result = Convert.ToBase64String(array); - return result; - } + using(Aes aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = iv; - public string Decrypt(string dataToDecrypt) - { - if (string.IsNullOrEmpty(key)) - throw new ArgumentNullException("EncryptionKey", "Please initialize your encryption key."); + ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV); + using(MemoryStream memoryStream = new MemoryStream()) + { + using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write)) + { + using(StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream)) + { + streamWriter.Write(dataToEncrypt); + } + array = memoryStream.ToArray(); + } + } + } + string result = Convert.ToBase64String(array); + return result; + } - if (string.IsNullOrEmpty(dataToDecrypt)) - return string.Empty; - - byte[] iv = new byte[16]; + public string Decrypt(string dataToDecrypt) + { + if(string.IsNullOrEmpty(key)) + throw new ArgumentNullException("EncryptionKey", "Please initialize your encryption key."); - using (Aes aes = Aes.Create()) - { - aes.Key = Encoding.UTF8.GetBytes(key); - aes.IV = iv; - ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); + if(string.IsNullOrEmpty(dataToDecrypt)) + return string.Empty; - var buffer = Convert.FromBase64String(dataToDecrypt); - using (MemoryStream memoryStream = new MemoryStream(buffer)) - { - using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read)) - { - using (StreamReader streamReader = new StreamReader((Stream)cryptoStream)) - { - return streamReader.ReadToEnd(); - } - } - } - } - } - } -} + byte[] iv = new byte[16]; + + using(Aes aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = iv; + ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); + + var buffer = Convert.FromBase64String(dataToDecrypt); + using(MemoryStream memoryStream = new MemoryStream(buffer)) + { + using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read)) + { + using(StreamReader streamReader = new StreamReader((Stream)cryptoStream)) + { + return streamReader.ReadToEnd(); + } + } + } + } + } + } + } diff --git a/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs.bak b/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs.bak new file mode 100644 index 0000000..5858425 --- /dev/null +++ b/EntityFramework.Core.EncryptDBColumn/Util/GenerateEncryptionProvider.cs.bak @@ -0,0 +1,77 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using EntityFrameworkCore.EncryptColumn.Interfaces; + +namespace EntityFrameworkCore.EncryptColumn.Util + { + public class GenerateEncryptionProvider:IEncryptionProvider + { + private readonly static string key = Initialize.EncryptionKey; + + public string Encrypt(string dataToEncrypt) + { + if(string.IsNullOrEmpty(key)) + throw new ArgumentNullException("EncryptionKey", "Please initialize your encryption key."); + + if(string.IsNullOrEmpty(dataToEncrypt)) + return string.Empty; + + byte[] iv = new byte[16]; + byte[] array; + + using(Aes aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = iv; + aes.Padding = PaddingMode.PKCS7; + ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV); + using(MemoryStream memoryStream = new MemoryStream()) + { + using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write)) + { + using(StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream)) + { + streamWriter.Write(dataToEncrypt); + } + array = memoryStream.ToArray(); + } + } + } + string result = Convert.ToBase64String(array); + return result; + } + + public string Decrypt(string dataToDecrypt) + { + if(string.IsNullOrEmpty(key)) + throw new ArgumentNullException("EncryptionKey", "Please initialize your encryption key."); + + if(string.IsNullOrEmpty(dataToDecrypt)) + return string.Empty; + + byte[] iv = new byte[16]; + + using(Aes aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = iv; + aes.Padding= PaddingMode.PKCS7; + ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV); + + var buffer = Convert.FromBase64String(dataToDecrypt); + using(MemoryStream memoryStream = new MemoryStream(buffer)) + { + using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read)) + { + using(StreamReader streamReader = new StreamReader((Stream)cryptoStream)) + { + return streamReader.ReadToEnd(); + } + } + } + } + } + } + } diff --git a/EntityFrameworkCore.EncryptColumn.sln b/EntityFrameworkCore.EncryptColumn.sln index cd1043b..dc9a1fa 100644 --- a/EntityFrameworkCore.EncryptColumn.sln +++ b/EntityFrameworkCore.EncryptColumn.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.809.7 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32210.238 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCore.EncryptColumn", "EntityFramework.Core.EncryptDBColumn\EntityFrameworkCore.EncryptColumn.csproj", "{0B0D7458-8F77-4F22-B6F6-38AA76637D47}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFrameworkCore.EncryptColumn", "EntityFramework.Core.EncryptDBColumn\EntityFrameworkCore.EncryptColumn.csproj", "{0B0D7458-8F77-4F22-B6F6-38AA76637D47}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EncryptColumnTest", "EncryptColumnTest\EncryptColumnTest.csproj", "{2A629569-23F7-48B8-9B6B-A5C52DF1DE71}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {0B0D7458-8F77-4F22-B6F6-38AA76637D47}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B0D7458-8F77-4F22-B6F6-38AA76637D47}.Release|Any CPU.ActiveCfg = Release|Any CPU {0B0D7458-8F77-4F22-B6F6-38AA76637D47}.Release|Any CPU.Build.0 = Release|Any CPU + {2A629569-23F7-48B8-9B6B-A5C52DF1DE71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A629569-23F7-48B8-9B6B-A5C52DF1DE71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A629569-23F7-48B8-9B6B-A5C52DF1DE71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A629569-23F7-48B8-9B6B-A5C52DF1DE71}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 5e699ce..43b68ed 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,14 @@ Hello, you can store your data in encrypted form in your database with this pack ## How to use? Install "[EntityFrameworkCore.EncryptColumn](https://www.nuget.org/packages/EntityFrameworkCore.EncryptColumn)" package to your project. -Specify your encryption key in the constructor method of your DbContext class and create a instance from the encryption provider. Yout encryption key must be 128 bit! +Specify your encryption key in the constructor method of your DbContext class and create a instance from the encryption provider. ```csharp private readonly IEncryptionProvider _provider; public ExampleDbContext() { - this._provider = new GenerateEncryptionProvider("example_encrypt_key"); + Initialize.EncryptionKey = "example_encrypt_key"; + this._provider = new GenerateEncryptionProvider(); } ``` Then specify that you will use an encryption provider in the "OnModelCreating" method.