使用NHibernate加密和解密数据

我正在编写一个可公开访问的Web应用程序,其中包含个人用户数据,例如姓名和出生日期,我需要以一种对可能访问原始数据的人很难解密的forms加密这些数据。 我正在使用Fluent NHibernate ,mySQL和C#3.5。

  1. 我应该使用什么方法进行行业标准加密和解密用户信息? 加密方法不应该依赖于数据库。

  2. 如何告诉nHibernate使用简单属性(如StorageType = StorageType.Encrypted对某些映射类进行透明加密/解密。 我不介意生成的数据库表只有一列或两列,或者每个加密字段一列。 根据我的发现,我应该从IUserDataType创建自己的数据类型并加密构造函数中的数据。 它是否正确?

在真正的蓝色彼得时尚中,这是我之前创造的一个这样做。 它依赖于提供者模式来获取加密算法,但您可以将其替换为您想要的任何内容。

这会在域对象中公开字符串属性,但会将其作为表示加密表单的二进制文件(字节数组)保留。 在我的提供者模式代码中,Encrypt接受一个字符串并返回一个字节数组,而Decrypt则相反。

 [Serializable] public class EncryptedStringType : PrimitiveType { public EncryptedStringType() : this(new BinarySqlType()) {} public EncryptedStringType(SqlType sqlType) : base(sqlType) {} public override string Name { get { return "String"; } } public override Type ReturnedClass { get { return typeof (string); } } public override Type PrimitiveClass { get { return typeof (string); } } public override object DefaultValue { get { return null; } } public override void Set(IDbCommand cmd, object value, int index) { if (cmd == null) throw new ArgumentNullException("cmd"); if (value == null) { ((IDataParameter)cmd.Parameters[index]).Value = null; } else { ((IDataParameter)cmd.Parameters[index]).Value = EncryptionManager.Provider.Encrypt((string)value); } } public override object Get(IDataReader rs, int index) { if (rs == null) throw new ArgumentNullException("rs"); var encrypted = rs[index] as byte[]; if (encrypted == null) return null; return EncryptionManager.Provider.Decrypt(encrypted); } public override object Get(IDataReader rs, string name) { return Get(rs, rs.GetOrdinal(name)); } public override object FromStringValue(string xml) { if (xml == null) { return null; } if (xml.Length % 2 != 0) { throw new ArgumentException( "The string is not a valid xml representation of a binary content.", "xml"); } var bytes = new byte[xml.Length / 2]; for (int i = 0; i < bytes.Length; i++) { string hexStr = xml.Substring(i * 2, (i + 1) * 2); bytes[i] = (byte)(byte.MinValue + byte.Parse(hexStr, NumberStyles.HexNumber, CultureInfo.InvariantCulture)); } return EncryptionManager.Provider.Decrypt(bytes); } public override string ObjectToSQLString(object value, Dialect dialect) { var bytes = value as byte[]; if (bytes == null) { return "NULL"; } var builder = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { string hexStr = (bytes[i] - byte.MinValue).ToString("x", CultureInfo.InvariantCulture); if (hexStr.Length == 1) { builder.Append('0'); } builder.Append(hexStr); } return builder.ToString(); } } 

我将创建一个EncryptionService,使用您想要的任何Key加密字符串。 然后我会在你的实体中制作2个属性。 NHibernate与(加密值)交互的一个和您(或其他开发人员)与之交互的另一个将自动加密值。

请参阅: http : //kockerbeck.blogspot.com/2009/08/fluent-nhibernate-encrypting-values.html

下面是一个示例EncryptionService,User实体和UserMap。

 public class User { private readonly EncryptionService _encryptionService = new EncryptionService(); public virtual int Id { get; set; } public virtual DateTime? DateOfBirth { get { return _encryptionService.DecryptObject(DateOfBirthEncrypted); } set { DateOfBirthEncrypted= _encryptionService.EncryptString(value.Value .ToString("yyyy-MM-dd HH:mm:ss")); } } [Obsolete("Use the 'DateOfBirth' property -- this property is only to be used by NHibernate")] public virtual string DateOfBirthEncrypted { get; set; } } public sealed class UserMap : ClassMap { public UserMap() { WithTable("dbo.[User]"); Id(x => x.Id, "[ID]"); Map(x => x.DateOfBirthEncrypted, "DOB"); } } 

和EncryptionService:

 using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Services { public class EncryptionService : IEncryptionService { ///  /// Decrypts a string ///  ///  ///  public String DecryptString(string encryptedString) { if (String.IsNullOrEmpty(encryptedString)) return String.Empty; try { using (TripleDESCryptoServiceProvider cypher = new TripleDESCryptoServiceProvider()) { PasswordDeriveBytes pdb = new PasswordDeriveBytes("ENTERAKEYHERE", new byte[0]); cypher.Key = pdb.GetBytes(16); cypher.IV = pdb.GetBytes(8); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, cypher.CreateDecryptor(), CryptoStreamMode.Write)) { byte[] data = Convert.FromBase64String(encryptedString); cs.Write(data, 0, data.Length); cs.Close(); return Encoding.Unicode.GetString(ms.ToArray()); } } } } catch { return String.Empty; } } ///  /// Encrypts a string ///  ///  public String EncryptString(string decryptedString) { if (String.IsNullOrEmpty(decryptedString)) return String.Empty; using (TripleDESCryptoServiceProvider cypher = new TripleDESCryptoServiceProvider()) { PasswordDeriveBytes pdb = new PasswordDeriveBytes("ENTERAKEYHERE", new byte[0]); cypher.Key = pdb.GetBytes(16); cypher.IV = pdb.GetBytes(8); using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, cypher.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] data = Encoding.Unicode.GetBytes(decryptedString); cs.Write(data, 0, data.Length); cs.Close(); return Convert.ToBase64String(ms.ToArray()); } } } } ///  /// Decrypts a given value as type of T, if unsuccessful the defaultValue is used ///  ///  ///  ///  ///  public T DecryptObject(object value, T defaultValue) { if (value == null) return defaultValue; try { Type conversionType = typeof(T); // Some trickery for Nullable Types if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { conversionType = new NullableConverter(conversionType).UnderlyingType; } return (T)Convert.ChangeType(DecryptString(Convert.ToString(value)), conversionType); } catch { // Do nothing } return defaultValue; } } }