使用 EF Core 3 解密数据
Decrypting data using EF Core 3
我正在尝试了解如何使用 EF Core 来解密使用对称密钥列加密的数据。在 SQL 服务器中,我会使用这些命令来获取我的数据:
OPEN SYMMETRIC KEY My_Key DECRYPTION BY CERTIFICATE myCert;
SELECT CONVERT(char, DecryptByKey(soc_sec_no))
FROM MyDatabase WHERE arid_identifier=0001882
如何从 EF Core 3 执行此操作?我从 Entity Framework 6(非核心)看到很多关于如何做到这一点的文章,我确实找到了 ,但代码对我不起作用。
我从 https://github.com/tkhadimullin/ef-core-custom-functions/tree/feature/ef-3.1-version 开始。
我已将更改放在 https://github.com/xanatos/ef-core-custom-functions/tree/feature/ef-3.1-version 上。请注意,有三个提交,一个用于 EF Core 3.1,一个用于 EF Core 3.1.11(无需更改),一个用于 EF Core 5.0.2(需要一些更改)。
遗憾的是,我必须更正代码中的各种小错误。关于OPEN SYMMETRIC KEY
的部分其实没有测试,被作者注释掉了。
必要的更改:
class 回购:
需要一个事务来将各种 SQL 命令放在一起。参数索引错误。我已经针对对称密钥名称和密码添加了一些针对注入攻击的保护(可能没用,因为这两件事应该受到很好的保护)
public IEnumerable<Model> GetAllById(int id)
{
// Transaction to keep together the two ExecuteSqlRaw with the query
DbContext.Database.BeginTransaction();
DbContext.Database.ExecuteSqlRaw($"DECLARE @Open NVARCHAR(MAX) = N'OPEN SYMMETRIC KEY ' + QUOTENAME(@p0, '[') + ' DECRYPTION BY PASSWORD = ' + QUOTENAME(@p1, '''') + N';'; EXEC sp_executesql @Open", SymmetricKeyName, SymmetricKeyPassword);
var filteredSet = Set.Include(x => x.Table2)
.Where(x => x.Id == id)
.Where(x => x.Table2.IsSomething)
.Select(m => new Model
{
Id = m.Id,
//Decrypted = EF.Functions.Decrypt(SymmetricKeyPassword, m.Encrypted).ToString(),
Decrypted = EF.Functions.DecryptByKey(m.Encrypted2).ToString(), // since the key's opened for session scope - just relying on it should do the trick
Table2 = m.Table2,
Encrypted = m.Encrypted,
}).ToList();
DbContext.Database.ExecuteSqlRaw($"DECLARE @Close NVARCHAR(MAX) = N'CLOSE SYMMETRIC KEY ' + QUOTENAME(@p0, '[') + ';'; EXEC sp_executesql @Close", SymmetricKeyName);
DbContext.Database.CommitTransaction();
return filteredSet;
}
class TranslateImpl:
解决了参数处理的一些问题(2 个参数并不总是存在,如果只有一个则方法崩溃)
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments)
{
if (method == _encryptMethod)
{
var args = new[] { arguments[1], arguments[2] }; // cut the first parameter from extension function
return _expressionFactory.Function(instance, "ENCRYPTBYPASSPHRASE", args, typeof(byte[]));
}
if (method == _decryptMethod)
{
var args = new[] { arguments[1], arguments[2] }; // cut the first parameter from extension function
return _expressionFactory.Function(instance, "DECRYPTBYPASSPHRASE", args, typeof(byte[]));
}
if (method == _decryptByKeyMethod)
{
var args = new[] { arguments[1], }; // cut the first parameter from extension function
return _expressionFactory.Function(instance, "DECRYPTBYKEY", args, typeof(byte[]));
}
return null;
}
脚本dbSchema.sql
脚本现在可以用两种不同的方式(密码或对称密钥)加密文本
CREATE SYMMETRIC KEY [TestKeyWithPassword] WITH ALGORITHM = AES_128 ENCRYPTION BY PASSWORD = 'TestPassword'
GO
OPEN SYMMETRIC KEY [TestKeyWithPassword] DECRYPTION BY PASSWORD = 'TestPassword'
GO
INSERT [dbo].[Models] ([Id], [Encrypted], [Table2Id])
VALUES (
1,
--ENCRYPTBYPASSPHRASE('TestPassword', 'Encrypted with Passphrapse'),
ENCRYPTBYKEY(key_GUID('TestKeyWithPassword'), 'Encrypted with Symmetric Key With Password'),
1)
关于 .ToString()
的重要说明
Decrypt
/DecryptByKey
后面有个.ToString()
。它被 EF Core 翻译成 CONVERT(VARCHAR(100), ...)
。如果你想要一些不同的东西,你必须创建一些 DBFunctions
来做(这很简单,以 DbFunctionsExtensions.Encrypt
中的例子为例,在我的 git 中完成)
关于保存时加密的重要说明
在所有这些中,我不确定您将如何实现加密部分。虽然您对 EF Core 生成的 SELECT
有一些控制,但对 INSERT
/UPDATE
.
的控制要小得多
我正在尝试了解如何使用 EF Core 来解密使用对称密钥列加密的数据。在 SQL 服务器中,我会使用这些命令来获取我的数据:
OPEN SYMMETRIC KEY My_Key DECRYPTION BY CERTIFICATE myCert;
SELECT CONVERT(char, DecryptByKey(soc_sec_no))
FROM MyDatabase WHERE arid_identifier=0001882
如何从 EF Core 3 执行此操作?我从 Entity Framework 6(非核心)看到很多关于如何做到这一点的文章,我确实找到了
我从 https://github.com/tkhadimullin/ef-core-custom-functions/tree/feature/ef-3.1-version 开始。
我已将更改放在 https://github.com/xanatos/ef-core-custom-functions/tree/feature/ef-3.1-version 上。请注意,有三个提交,一个用于 EF Core 3.1,一个用于 EF Core 3.1.11(无需更改),一个用于 EF Core 5.0.2(需要一些更改)。
遗憾的是,我必须更正代码中的各种小错误。关于OPEN SYMMETRIC KEY
的部分其实没有测试,被作者注释掉了。
必要的更改:
class 回购:
需要一个事务来将各种 SQL 命令放在一起。参数索引错误。我已经针对对称密钥名称和密码添加了一些针对注入攻击的保护(可能没用,因为这两件事应该受到很好的保护)
public IEnumerable<Model> GetAllById(int id)
{
// Transaction to keep together the two ExecuteSqlRaw with the query
DbContext.Database.BeginTransaction();
DbContext.Database.ExecuteSqlRaw($"DECLARE @Open NVARCHAR(MAX) = N'OPEN SYMMETRIC KEY ' + QUOTENAME(@p0, '[') + ' DECRYPTION BY PASSWORD = ' + QUOTENAME(@p1, '''') + N';'; EXEC sp_executesql @Open", SymmetricKeyName, SymmetricKeyPassword);
var filteredSet = Set.Include(x => x.Table2)
.Where(x => x.Id == id)
.Where(x => x.Table2.IsSomething)
.Select(m => new Model
{
Id = m.Id,
//Decrypted = EF.Functions.Decrypt(SymmetricKeyPassword, m.Encrypted).ToString(),
Decrypted = EF.Functions.DecryptByKey(m.Encrypted2).ToString(), // since the key's opened for session scope - just relying on it should do the trick
Table2 = m.Table2,
Encrypted = m.Encrypted,
}).ToList();
DbContext.Database.ExecuteSqlRaw($"DECLARE @Close NVARCHAR(MAX) = N'CLOSE SYMMETRIC KEY ' + QUOTENAME(@p0, '[') + ';'; EXEC sp_executesql @Close", SymmetricKeyName);
DbContext.Database.CommitTransaction();
return filteredSet;
}
class TranslateImpl:
解决了参数处理的一些问题(2 个参数并不总是存在,如果只有一个则方法崩溃)
public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments)
{
if (method == _encryptMethod)
{
var args = new[] { arguments[1], arguments[2] }; // cut the first parameter from extension function
return _expressionFactory.Function(instance, "ENCRYPTBYPASSPHRASE", args, typeof(byte[]));
}
if (method == _decryptMethod)
{
var args = new[] { arguments[1], arguments[2] }; // cut the first parameter from extension function
return _expressionFactory.Function(instance, "DECRYPTBYPASSPHRASE", args, typeof(byte[]));
}
if (method == _decryptByKeyMethod)
{
var args = new[] { arguments[1], }; // cut the first parameter from extension function
return _expressionFactory.Function(instance, "DECRYPTBYKEY", args, typeof(byte[]));
}
return null;
}
脚本dbSchema.sql
脚本现在可以用两种不同的方式(密码或对称密钥)加密文本
CREATE SYMMETRIC KEY [TestKeyWithPassword] WITH ALGORITHM = AES_128 ENCRYPTION BY PASSWORD = 'TestPassword'
GO
OPEN SYMMETRIC KEY [TestKeyWithPassword] DECRYPTION BY PASSWORD = 'TestPassword'
GO
INSERT [dbo].[Models] ([Id], [Encrypted], [Table2Id])
VALUES (
1,
--ENCRYPTBYPASSPHRASE('TestPassword', 'Encrypted with Passphrapse'),
ENCRYPTBYKEY(key_GUID('TestKeyWithPassword'), 'Encrypted with Symmetric Key With Password'),
1)
关于 .ToString()
的重要说明Decrypt
/DecryptByKey
后面有个.ToString()
。它被 EF Core 翻译成 CONVERT(VARCHAR(100), ...)
。如果你想要一些不同的东西,你必须创建一些 DBFunctions
来做(这很简单,以 DbFunctionsExtensions.Encrypt
中的例子为例,在我的 git 中完成)
关于保存时加密的重要说明
在所有这些中,我不确定您将如何实现加密部分。虽然您对 EF Core 生成的 SELECT
有一些控制,但对 INSERT
/UPDATE
.