简体   繁体   English

使用 EF Core 3 解密数据

[英]Decrypting data using EF Core 3

I am trying to find out how to use EF Core to decrypt data that is column encrypted with a Symmetric Key.我正在尝试了解如何使用 EF Core 解密使用对称密钥加密的列数据。 In SQL Server, I would use these commands to get my data:在 SQL 服务器中,我会使用这些命令来获取我的数据:

OPEN SYMMETRIC KEY My_Key DECRYPTION BY CERTIFICATE myCert;
SELECT  CONVERT(char, DecryptByKey(soc_sec_no))
FROM MyDatabase WHERE arid_identifier=0001882

How can I do this from EF Core 3?如何从 EF Core 3 执行此操作? I see a lot of articles on how to do this from Entity Framework 6 (non-core) and I did find this question , but the code did not work for me.我从 Entity Framework 6 (non-core) 看到很多关于如何做到这一点的文章,我确实找到了这个问题,但代码对我不起作用。

I started with https://github.com/tkhadimullin/ef-core-custom-functions/tree/feature/ef-3.1-version .我从https://github.com/tkhadimullin/ef-core-custom-functions/tree/feature/ef-3.1-version开始。

I've put the changes on https://github.com/xanatos/ef-core-custom-functions/tree/feature/ef-3.1-version .我已将更改放在https://github.com/xanatos/ef-core-custom-functions/tree/feature/ef-3.1-version上。 Note that there are three commits, one for EF Core 3.1, one for EF Core 3.1.11 (no changes necessary), one for EF Core 5.0.2 (some changes necessary).请注意,有三个提交,一个用于 EF Core 3.1,一个用于 EF Core 3.1.11(无需更改),一个用于 EF Core 5.0.2(需要进行一些更改)。

Sadly there were various small bugs in the code that I had to correct.可悲的是,我必须纠正代码中的各种小错误。 The part about OPEN SYMMETRIC KEY in fact wasn't tested and was commented out by the author.关于OPEN SYMMETRIC KEY的部分其实是没有测试过的,被作者注释掉了。

Changes necessary:必要的更改:

class Repo: class 回购:

A transaction is needed to keep together the various SQL commands.需要一个事务来将各种 SQL 命令放在一起。 The indexes of the parameters are wrong.参数索引错误。 I've added some protection against injection attacks vs the symmetric key name and password (probably useless because these two things should be very protected)我添加了一些针对对称密钥名称和密码的注入攻击的保护(可能没用,因为这两件事应该受到很好的保护)

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: class TranslateImpl:

Fixed some problems with the handling of arguments (2 arguments aren't always present, and if there is only one the method crashes)修复了处理 arguments 的一些问题(2 个 arguments 并不总是存在,如果只有一个则方法崩溃)

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;
}

script dbSchema.sql脚本 dbSchema.sql

The script can now encrypt text in two different ways (passphrase or symmetric key)该脚本现在可以以两种不同的方式加密文本(密码或对称密钥)

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)

Big note about.ToString()关于.ToString() 的重要说明

There is a .ToString() after the Decrypt / DecryptByKey .Decrypt / DecryptByKey之后有一个.ToString() It is translated to a CONVERT(VARCHAR(100), ...) by EF Core.它由 EF Core 转换为CONVERT(VARCHAR(100), ...) If you want something different you'll have to create some DBFunctions to do it (it is quite simple, take the example from DbFunctionsExtensions.Encrypt , done in my git)如果你想要一些不同的东西,你必须创建一些DBFunctions来做到这一点(这很简单,以DbFunctionsExtensions.Encrypt ,在我的 git 中完成)

Big note about encrypting on save关于保存时加密的重要说明

In all of this, I'm not sure how you would implement the encryption part.在所有这些中,我不确定您将如何实现加密部分。 While you have some control on the SELECT generated by EF Core, you have much smaller control on the INSERT / UPDATE .虽然您对 EF Core 生成的SELECT有一些控制权,但您对INSERT / UPDATE的控制权要小得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM