绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
在EF Core中为数据表按列加密存储
2023-04-06 17:53:56

假设有User表

public class User : Entity<int>
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public string Name { get; set; }
    public string IdentificationNumber { get; set; }
}

其中有身份证号码IdentificationNumber列,需要加密存储,该如何实现?

创建一个值转换器,继承ValueConverter<TModel, string>类型。其中泛型TModel为实体中属性的类型。

转换器将实体中属性类型,通过AES加密算法,转换为Base64编码字符串类型,存储到数据库中。当从数据库中读取数据时,再通过AES解密算法,将Base64编码字符串类型转换为实体中属性类型。

若实体类型为byte[],则不需要转换为Base64编码字符串类型,直接对二进制数据进行加密和解密。此转换器可以用于加密存储图片、文件等二进制数据。

AES加密算法是一种对称加密算法,加密和解密使用相同的密钥。在加密和解密时,需要指定密钥、初始向量、盐值等参数。在转换器中,将这些参数设置为静态属性,方便在使用时,进行修改。

代码如下:

public class EncryptionConverter<TModel> : ValueConverter<TModel, string>
{

    public const int DefaultKeysize = 256;

    public static string DefaultPassPhrase { get; set; }

    public static byte[] DefaultInitVectorBytes { get; set; }

    public static byte[] DefaultSalt { get; set; }
    public EncryptionConverter()
        : base(
            x => Encrypt(x),
            x => Decrypt(x))
    {
        DefaultPassPhrase = "gsKnGZ041HLL4IM8";
        DefaultInitVectorBytes = Encoding.ASCII.GetBytes("jkE49230Tf093b42");
        DefaultSalt = Encoding.ASCII.GetBytes("hgt!16kl");
    }

    private static string Encrypt(TModel input)
    {
        try
        {
            byte[] inputData = input switch
            {
                string => Encoding.UTF8.GetBytes(input.ToString()),
                byte[] => input as byte[],
                _ => null,
            };

            using (var password = new Rfc2898DeriveBytes(DefaultPassPhrase, DefaultSalt))
            {
                var keyBytes = password.GetBytes(DefaultKeysize / 8);
                using (var symmetricKey = Aes.Create())
                {
                    symmetricKey.Mode = CipherMode.CBC;
                    using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, DefaultInitVectorBytes))
                    {
                        using (var memoryStream = new MemoryStream())
                        {
                            using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                            {
                                cryptoStream.Write(inputData, , inputData.Length);
                                cryptoStream.FlushFinalBlock();
                                var cipherTextBytes = memoryStream.ToArray();
                                var rawString = Convert.ToBase64String(cipherTextBytes);
                                return rawString;

                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {              
            LogHelper.LogException(ex);
            return input.ToString();              
        }
        
    }

    private static TModel Decrypt(string input)
    {
        try
        {
            var cipherTextBytes = Convert.FromBase64String(input);

            using (var password = new Rfc2898DeriveBytes(DefaultPassPhrase, DefaultSalt))
            {
                var keyBytes = password.GetBytes(DefaultKeysize / 8);
                using (var symmetricKey = Aes.Create())
                {
                    symmetricKey.Mode = CipherMode.CBC;
                    using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, DefaultInitVectorBytes))
                    {
                        using (var memoryStream = new MemoryStream(cipherTextBytes))
                        {
                            using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                            {
                                var plainTextBytes = new byte[cipherTextBytes.Length];
                                int totalDecryptedByteCount = ;
                                while (totalDecryptedByteCount < plainTextBytes.Length)
                                {
                                    var decryptedByteCount = cryptoStream.Read(
                                        plainTextBytes,
                                        totalDecryptedByteCount,
                                        plainTextBytes.Length - totalDecryptedByteCount
                                    );

                                    if (decryptedByteCount == )
                                    {
                                        break;
                                    }

                                    totalDecryptedByteCount += decryptedByteCount;
                                }
                                byte[] outputData = null;
                                if (typeof(TModel) == typeof(string))
                                {
                                    outputData = Encoding.UTF8.GetBytes(plainTextBytes.ToString());
                                }
                                else if (typeof(TModel) == typeof(byte[]))
                                {
                                    outputData = plainTextBytes as byte[];
                                };

                                var rawString = Encoding.UTF8.GetString(outputData, , totalDecryptedByteCount);

                                return (TModel)Convert.ChangeType(rawString, typeof(TModel));

                            }
                        }
                    }
                }
            }

        }
        catch (Exception ex)
        {
        	// 记录异常
            // LogHelper.LogException(ex);
            return (TModel)Convert.ChangeType(input, typeof(TModel));
        }

    }
}

DbContext中,重写OnModelCreating方法,为User表的IdentificationNumber列,添加值转换器。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<User>().Property(c => c.IdentificationNumber).HasConversion<EncryptionConverter<string>>();
}

再次调用Add方法插入数据时,可以看到IdentificationNumber列已被加密了

分享好友

分享这个小栈给你的朋友们,一起进步吧。

.NET中大型研发必备
创建时间:2022-04-09 00:21:16
本系列文章适合有初/.NET知识的同学阅读(请在电脑上打开页面,获取更好的阅读效果)。 (1)本系列文章,旨在讲述研发一个中大型项目所需要了解的一系列“基本构件”,并提供这些“基本构件”在全网的【简单】、【快速】使用方法!!(并不深究技术原理) (2)通过阅读本系列文章,能让你在“正规”项目研发方面快速入门+进阶,并能达成“小团队构建大网站”的目的。 (3)本系列文章采用的技术,已成功应用到人工智能、产业互联网、社区电商、游戏、金融风控、智慧医疗、等项目上。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • 红色侦察兵
    栈主

小栈成员

查看更多
  • miemieMIA
  • LCR_
  • xsy028
  • ?时光与海?
戳我,来吐槽~