You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+16-7Lines changed: 16 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,7 @@ When you need to store sensitive data in your database, you may want to encrypt
15
15
encrypt data, it becomes impossible to query it by EF-core, which is not really convenient if you want to encrypt, for example, email addresses, or SSNs
16
16
AND then filter entities by them.
17
17
18
-
This library has support for hashing the sensitive data and storing their (sha256) hashes in a shadow property alongside the encrypted data.
18
+
This library has support for hashing the salted sensitive data and storing their (Hmac Sha256) hashes in a shadow property alongside the encrypted data.
19
19
This allows you to query for the encrypted properties without decrypting them first. using `QueryableExt.WherePdEquals`
> If you want to query for encrypted properties, along with marking your properties as queryable, you **MUST** set
88
+
> `EFCORE_DATA_PROTECTION__HASHING_SALT` in the environment. I could suggest you setting it to a random guid, or a very long string.
89
+
> This was implemented to prevent rainbow attacks on sensitive data.
90
+
86
91
> [!TIP]
87
92
> See the [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) for more
88
93
> information on **how to configure the data protection** services, and how to store your encryption keys securely.
@@ -110,17 +115,21 @@ Using the EncryptedAttribute:
110
115
```csharp
111
116
classUser
112
117
{
113
-
[Encrypt(IsQueryable=true, IsUnique=true)]
118
+
[Encrypt(isQueryable:true, isUnique:true)]
114
119
publicstringSocialSecurityNumber { get; set; }
115
120
116
-
[Encrypt(IsQueryable=false, IsUnique=false)]
121
+
[Encrypt(isQueryable:false, isUnique:false)]
117
122
publicbyte[] IdPicture { get; set; }
118
123
}
119
124
```
120
125
121
126
> [!TIP]
122
-
> By default `IsQueryable` and `IsUnique` are set to `true`, you can omit them if you want to use the default values.
123
-
> If you have a property that is marked as `IsQueryable = true` and you want to query it, you **MUST** call `AddDataProtectionInterceptors` in your `DbContext` configuration.
127
+
> `isQueryable` marks a property as queryable (this will generate a shadow hash) <br/>
128
+
> `isUnique` marks a property as unique, and adds a unique index on the property. An index is added by default, even if the property is not marked as unique. However, that default index is not Unique.
129
+
130
+
> [!WARNING]
131
+
> If you have a property that is marked as queryable, you **MUST** call `AddDataProtectionInterceptors` in your `DbContext` configuration.
132
+
> And you **MUST** set `EFCORE_DATA_PROTECTION__HASHING_SALT` in the environment. Otherwise, an exception will be thrown while trying to save the entity.
124
133
125
134
Using the FluentApi (in your `DbContext.OnModelCreating` method):
126
135
```csharp
@@ -148,7 +157,7 @@ var foo = await DbContext.Users
148
157
```
149
158
150
159
> [!WARNING]
151
-
> The `QueryableExt.WherePdEquals` method is only available for properties that are marked as Queryable using the `[Encrypt(IsQueryable = true)]` attribute or the
160
+
> The `QueryableExt.WherePdEquals` method is only available for properties that are marked as Queryable using the `[Encrypt(isQueryable: true)]` attribute or the
152
161
> `IsEncryptedQueryable()` method.
153
162
154
163
> [!CAUTION]
@@ -157,7 +166,7 @@ var foo = await DbContext.Users
157
166
158
167
> [!NOTE]
159
168
> The `WherePdEquals` extension method generates an expression like this one under the hood:<br/>
Copy file name to clipboardExpand all lines: src/Klean.EntityFrameworkCore.DataProtection/EncryptAttribute.cs
+17-2Lines changed: 17 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -15,10 +15,25 @@ public sealed class EncryptAttribute : Attribute
15
15
/// Gets a boolean value indicating if this property can be queried from the database.
16
16
/// Because of how data protection in this library is implemented, if you want your protected property to be queryable, you must ensure that the property is a string or byte[].
17
17
/// </summary>
18
-
publicboolIsQueryable{get;init;}=true;
18
+
internalboolIsQueryable{get;init;}
19
19
20
20
/// <summary>
21
21
/// Gets a boolean value indicating if this property should have a unique index.
22
22
/// </summary>
23
-
publicboolIsUnique{get;init;}=true;
23
+
internalboolIsUnique{get;init;}
24
+
25
+
/// <summary>
26
+
/// Marks a property as encrypted.
27
+
/// Optionally choose if you want your property to be queryable or not.
28
+
/// Optionally choose if you want your properties to have a Unique Index or not.
29
+
/// </summary>
30
+
/// <remarks>
31
+
/// Because of how data protection in this library is implemented, if you want your protected property to be queryable, you must ensure that the property is a string or byte[].
32
+
/// Please note, you must set `EFCORE_DATA_PROTECTION__HASHING_SALT` in the environment to be able to query for data.
??thrownewInvalidOperationException($"{EnvKey} is not present in the environment, please set it to a strong value and keep it safe, otherwise querying will not work.");
Copy file name to clipboardExpand all lines: src/Klean.EntityFrameworkCore.DataProtection/Interceptors/ShadowHashSynchronizingSaveChangesInterceptor.cs
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -62,7 +62,7 @@ from prop in entityType.GetProperties()
0 commit comments