假设有User表
1 2 3 4 5 6 7
| 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加密算法是一种对称加密算法,加密和解密使用相同的密钥。在加密和解密时,需要指定密钥、初始向量、盐值等参数。在转换器中,将这些参数设置为静态属性,方便在使用时,进行修改。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| 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)) { var outputData = Encoding.UTF8.GetString(plainTextBytes, 0, totalDecryptedByteCount); return (TModel)Convert.ChangeType(outputData, typeof(TModel));
} else if (typeof(TModel) == typeof(byte[])) { var outputData = plainTextBytes as byte[]; return (TModel)Convert.ChangeType(outputData, typeof(TModel));
}; return default;
} } } } }
} catch (Exception ex) { return (TModel)Convert.ChangeType(input, typeof(TModel)); }
} }
|
在DbContext
中,重写OnModelCreating
方法,为User表的IdentificationNumber列,添加值转换器。
1 2 3 4 5 6
| protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<User>().Property(c => c.IdentificationNumber).HasConversion<EncryptionConverter<string>>(); }
|
再次调用Add方法插入数据时,可以看到IdentificationNumber列已被加密了