-
-
Save albertbori/e95860644e69c1572441 to your computer and use it in GitHub Desktop.
public class MyDB : IdentityDbContext<User> | |
{ | |
//DBSet properties go here | |
public MyDB() | |
{ | |
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += new ObjectMaterializedEventHandler(ObjectMaterialized); | |
} | |
#region Encryption | |
public override int SaveChanges() | |
{ | |
var contextAdapter = ((IObjectContextAdapter)this); | |
contextAdapter.ObjectContext.DetectChanges(); //force this. Sometimes entity state needs a handle jiggle | |
var pendingEntities = contextAdapter.ObjectContext.ObjectStateManager | |
.GetObjectStateEntries(EntityState.Added | EntityState.Modified) | |
.Where(en => !en.IsRelationship).ToList(); | |
foreach (var entry in pendingEntities) //Encrypt all pending changes | |
EncryptEntity(entry.Entity); | |
int result = base.SaveChanges(); | |
foreach (var entry in pendingEntities) //Decrypt updated entities for continued use | |
DecryptEntity(entry.Entity); | |
return result; | |
} | |
public override async Task<int> SaveChangesAsync(System.Threading.CancellationToken cancellationToken) | |
{ | |
var contextAdapter = ((IObjectContextAdapter)this); | |
contextAdapter.ObjectContext.DetectChanges(); //force this. Sometimes entity state needs a handle jiggle | |
var pendingEntities = contextAdapter.ObjectContext.ObjectStateManager | |
.GetObjectStateEntries(EntityState.Added | EntityState.Modified) | |
.Where(en => !en.IsRelationship).ToList(); | |
foreach (var entry in pendingEntities) //Encrypt all pending changes | |
EncryptEntity(entry.Entity); | |
var result = await base.SaveChangesAsync(cancellationToken); | |
foreach (var entry in pendingEntities) //Decrypt updated entities for continued use | |
DecryptEntity(entry.Entity); | |
return result; | |
} | |
void ObjectMaterialized(object sender, ObjectMaterializedEventArgs e) | |
{ | |
DecryptEntity(e.Entity); | |
} | |
private void EncryptEntity(object entity) | |
{ | |
//Get all the properties that are encryptable and encrypt them | |
var encryptedProperties = entity.GetType().GetProperties() | |
.Where(p => p.GetCustomAttributes(typeof(Encrypted), true).Any(a => p.PropertyType == typeof(String))); | |
foreach (var property in encryptedProperties) | |
{ | |
string value = property.GetValue(entity) as string; | |
if (!String.IsNullOrEmpty(value)) | |
{ | |
string encryptedValue = EncryptionService.Encrypt(value); | |
property.SetValue(entity, encryptedValue); | |
} | |
} | |
} | |
private void DecryptEntity(object entity) | |
{ | |
//Get all the properties that are encryptable and decyrpt them | |
var encryptedProperties = entity.GetType().GetProperties() | |
.Where(p => p.GetCustomAttributes(typeof(Encrypted), true).Any(a => p.PropertyType == typeof(String))); | |
foreach (var property in encryptedProperties) | |
{ | |
string encryptedValue = property.GetValue(entity) as string; | |
if (!String.IsNullOrEmpty(encryptedValue)) | |
{ | |
string value = EncryptionService.Decrypt(encryptedValue); | |
this.Entry(entity).Property(property.Name).OriginalValue = value; | |
this.Entry(entity).Property(property.Name).IsModified = false; | |
} | |
} | |
} | |
#endregion Encryption | |
} |
Hi,
Thank you for this solution, but it don't fit to my case as I'm using EF proxy and Custom Attributes on the POCO are not transfer to the proxy.
Could you, please, show a way to achieve this?
Thanks in advance.
Thank you
I have developed an Entity Framework Core plugin that handles data encryption of a string
field using a custom attribute. Actually there is only the AES encryption provider available, but you can easily implement new encryption providers. Check it out here: https://github.com/Eastrall/EntityFrameworkCore.DataEncryption
Also, it's compatible with EF Core 2 and 3.
Quick example:
public class UserEntity
{
public int Id { get; set; }
[Encrypted]
public string Username { get; set; }
[Encrypted]
public string Password { get; set; }
public int Age { get; set; }
}
public class DatabaseContext : DbContext
{
// Get key and IV from a Base64String or any other ways.
// You can generate a key and IV using "AesProvider.GenerateKey()"
private readonly byte[] _encryptionKey = ...;
private readonly byte[] _encryptionIV = ...;
private readonly IEncryptionProvider _provider;
public DbSet<UserEntity> Users { get; set; }
public DatabaseContext(DbContextOptions options)
: base(options)
{
this._provider = new AesProvider(this._encryptionKey, this._encryptionIV);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseEncryption(this._provider);
}
}
how does search (like search )in encrypted columns work in this solution?
When you define a string
property as [Encrypted]
, the DataEncryption
extension will save the encrypted data into the column instead of the raw data.
When you read the data from your code, it will appear as raw data instead of encrypted. So you can easily do your search through code.
Im using MyDB.cs code
Below is my code for search. But still not able to filter
transactions = db.OverseasAttractionTransactions.Where(t => t.CrOrderNumber.ToLower().Contains(searchKeyword) || t.CustomerEmail.ToLower().Contains(searchKeyword) ||
(t.CustomerFirstName).ToLower().Contains(searchKeyword) || t.CustomerLastName.ToLower().Contains(searchKeyword) ||
t.CustomerNricOrPassport.ToLower().Contains(searchKeyword) || t.CustomerPhoneNumber.ToLower().Contains(searchKeyword) ||
t.DiscountCode.ToLower().Contains(searchKeyword) || t.ReferenceNumber.ToLower().Contains(searchKeyword))
.OrderBy(t => t.PurchaseDateTime).ToList();
It's not working. I can't create provider and can't make migration.
Something wrong with this code and attribute.
modelBuilder.UseEncryption(this._provider); - this._provider always null while attempt to create migration.
Version 3.0 is on the way. It will fix the issue : SoftFluent/EntityFrameworkCore.DataEncryption#25
Thanks. I will try tomorrow :) This needs for me
Im using MyDB.cs code Below is my code for search. But still not able to filter transactions = db.OverseasAttractionTransactions.Where(t => t.CrOrderNumber.ToLower().Contains(searchKeyword) || t.CustomerEmail.ToLower().Contains(searchKeyword) || (t.CustomerFirstName).ToLower().Contains(searchKeyword) || t.CustomerLastName.ToLower().Contains(searchKeyword) || t.CustomerNricOrPassport.ToLower().Contains(searchKeyword) || t.CustomerPhoneNumber.ToLower().Contains(searchKeyword) || t.DiscountCode.ToLower().Contains(searchKeyword) || t.ReferenceNumber.ToLower().Contains(searchKeyword)) .OrderBy(t => t.PurchaseDateTime).ToList();
@Eastrall can you answer this question please i cant search on contains filter
how does search in encrypted columns work in this solution?