Encrypting and decrypting data using NHibernate

后端 未结 2 1793
渐次进展
渐次进展 2021-02-02 04:01

I\'m writing a publicly accessible web application which will contain personal user data, such as names and birth dates, and I\'m required to encrypt this data in a form that w

相关标签:
2条回答
  • 2021-02-02 04:31

    In true Blue Peter fashion, here's one I created earlier to do just this. It relies on a provider pattern to get the encryption algorithm but you could replace this with whatever you want.

    This exposes a string property in your domain object, but persists it as a binary (array of bytes) representing the encrypted form. In my provider pattern code, Encrypt takes a string and returns a byte array, and Decrypt does the opposite.

    [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();
        }
    }
    
    0 讨论(0)
  • 2021-02-02 04:37

    I would create an EncryptionService that encrypts strings using whatever Key you'd like. Then I would make 2 properties in your entity. One that NHibernate interacts with (Encrypted values) and another that you (or other developers) interact with that will automatically encrypt the values.

    See: http://kockerbeck.blogspot.com/2009/08/fluent-nhibernate-encrypting-values.html

    A sample EncryptionService, User entity and UserMap are below.

    public class User
    {
       private readonly EncryptionService _encryptionService =
                       new EncryptionService();
       public virtual int Id { get; set; }
       public virtual DateTime? DateOfBirth
       {
         get
         {
           return _encryptionService.DecryptObject<DateTime?>(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<User>
    {
      public UserMap()
      {
        WithTable("dbo.[User]");
        Id(x => x.Id, "[ID]");
        Map(x => x.DateOfBirthEncrypted, "DOB");
      }
    }
    

    And the EncryptionService:

    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace Services
    {
        public class EncryptionService : IEncryptionService 
        {
            /// <summary>
            /// Decrypts a string 
            /// </summary>
            /// <param name="encryptedString"></param>
            /// <returns></returns>
            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;
                }
            }
    
            /// <summary>
            /// Encrypts a string
            /// </summary>
            /// <param name="decryptedString"
            /// <returns></returns>
            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());
                        }
                    }
                }
            }
    
            /// <summary>
            /// Decrypts a given value as type of T, if unsuccessful the defaultValue is used
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="value"></param>
            /// <param name="defaultValue"></param>
            /// <returns></returns>
            public T DecryptObject<T>(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;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题