4

在EF Core中为数据表按列加密存储 - 林晓lx

 1 year ago
source link: https://www.cnblogs.com/jevonsflash/p/17288803.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在EF Core中为数据表按列加密存储

假设有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列,需要加密存储,该如何实现?
![在这里插入图片描述](https://img-blog.csdnimg.cn/a9edb9793cc841ff91391ec7d4d298d7.png

在这里插入图片描述

创建一个值转换器,继承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, 0, 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 = 0;
                                while (totalDecryptedByteCount < plainTextBytes.Length)
                                {
                                    var decryptedByteCount = cryptoStream.Read(
                                        plainTextBytes,
                                        totalDecryptedByteCount,
                                        plainTextBytes.Length - totalDecryptedByteCount
                                    );

                                    if (decryptedByteCount == 0)
                                    {
                                        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, 0, 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列已被加密了

在这里插入图片描述


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK