Nhibernate 3.0 cookbook学习笔记 创建一个加密类

为数据库中的关键字段进行加密是必不可少的,特别是一些用户密码,银行卡账号等。现在我们来说一下如何在Nhibernate中创建一个加密类来为数据库中的关键字段加密。

1 创建一个接口:IEncryptor

public interface IEncryptor
    {
        string Encrypt(string plainText);
        string Decrypt(string encryptedText);
        string EncryptionKey { get; set; }
    }

2 再创建一个继承它的子类:SymmetricEncryptorBase

public class SymmetricEncryptorBase : IEncryptor
    {
        private readonly SymmetricAlgorithm _cryptoProvider;
        private byte[] _myBytes;
        protected SymmetricEncryptorBase(
        SymmetricAlgorithm cryptoProvider)
        {
            _cryptoProvider = cryptoProvider;
        }

        #region IEncryptor 成员
        public string EncryptionKey { get; set; }      

        /// <summary>
        /// 加密,利用CryptoStream
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public string Encrypt(string plainText)
        {
            var bytes = GetEncryptionKeyBytes();
            using (var memoryStream = new MemoryStream())
            {
                ICryptoTransform encryptor = _cryptoProvider
                .CreateEncryptor(bytes, bytes);
                using (var cryptoStream = new CryptoStream(
                memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    using (var writer = new StreamWriter(cryptoStream))
                    {
                       
                        writer.Write(plainText);
                        writer.Flush();
                        cryptoStream.FlushFinalBlock();
                        return Convert.ToBase64String(
                        memoryStream.GetBuffer(),
                        0,
                        (int)memoryStream.Length);
                    }
                }
            }
        }

        //获取密钥
        private byte[] GetEncryptionKeyBytes()
        {
            if (_myBytes == null)
                _myBytes = Encoding.ASCII.GetBytes(EncryptionKey);
            return _myBytes;
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="encryptedText"></param>
        /// <returns></returns>
        public string Decrypt(string encryptedText)
        {
            var bytes = GetEncryptionKeyBytes();
            using (var memoryStream = new MemoryStream(
            Convert.FromBase64String(encryptedText)))
            {
                ICryptoTransform decryptor = _cryptoProvider
                .CreateDecryptor(bytes, bytes);
                using (var cryptoStream = new CryptoStream(
                memoryStream, decryptor, CryptoStreamMode.Read))
                {
                    using (var reader = new StreamReader(cryptoStream))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
        }

        #endregion
    }

3 再创建一个类:DESEncryptor

 public class DESEncryptor : SymmetricEncryptorBase
    {
        public DESEncryptor()
            : base(new DESCryptoServiceProvider())
        { }
    }

4 再新建一个类:EncryptedString,通过这个类来调用前面的DESEncryptor来加密解密字符串

public class EncryptedString : IUserType, IParameterizedType
    {
        private IEncryptor _encryptor;
        public object NullSafeGet( IDataReader rs, string[] names, object owner)
        {
            //treat for the posibility of null values
            object passwordString =
            NHibernateUtil.String.NullSafeGet(rs, names[0]);
            if (passwordString != null)
            {
                return _encryptor.Decrypt((string)passwordString);
            }
            return null;
        }
        public void NullSafeSet(IDbCommand cmd,object value,int index)
        {
            if (value == null)
            {
                NHibernateUtil.String.NullSafeSet(cmd, null, index);
                return;
            }
            string encryptedValue = _encryptor.Encrypt((string)value);
            NHibernateUtil.String.NullSafeSet(
            cmd, encryptedValue, index);
        }
        public object DeepCopy(object value)
        {
            return value == null ? null :
        string.Copy((string)value);
        }
        public object Replace(object original,
        object target, object owner)
        {
            return original;
        }
        public object Assemble(object cached, object owner)
        {
            return DeepCopy(cached);
        }

        public object Disassemble(object value)
        {
            return DeepCopy(value);
        }
        public SqlType[] SqlTypes
        {
            get
            {
                return new[] { new SqlType(DbType.String) };
            }
        }
        public Type ReturnedType
        {
            get { return typeof(string); }
        }
        public bool IsMutable
        {
            get { return false; }
        }
        public new bool Equals(object x, object y)
        {
            if (ReferenceEquals(x, y))
            {
                return true;
            }
            if (x == null || y == null)
            {
                return false;
            }
            return x.Equals(y);
        }
        public int GetHashCode(object x)
        {
            if (x == null)
            {
                throw new ArgumentNullException("x");
            }
            return x.GetHashCode();
        }
        public void SetParameterValues(
        IDictionary<string, string> parameters)
        {
            if (parameters != null)
            {
                var encryptorTypeName = parameters["encryptor"];
                _encryptor = !string.IsNullOrEmpty(encryptorTypeName)
                ? (IEncryptor)Instantiate(encryptorTypeName)
                : new DESEncryptor();
                var encryptionKey = parameters["encryptionKey"];
                if (!string.IsNullOrEmpty(encryptionKey))
                    _encryptor.EncryptionKey = encryptionKey;
            }
            else
            {
                _encryptor = new DESEncryptor();
            }
        }
        private static object Instantiate(string typeName)
        {
            var type = Type.GetType(typeName);
            return Activator.CreateInstance(type);
        }
    }

 OK.这个加密类到此就完成了。现在我们来创建一个Account对象来测试。

public class Account
    {
        public virtual Guid Id { get; set; }
        public virtual string EMail { get; set; }
        public virtual string Name { get; set; }
        public virtual string CardNumber { get; set; }
        public virtual int ExpirationMonth { get; set; }
        public virtual int ExpirationYear { get; set; }
        public virtual string ZipCode { get; set; }
    }

重要的是定义相应的Account.hbm.xml文件:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="EncryptedStringExample"
namespace="EncryptedStringExample">
  <typedef
  name="encrypted"
  class="EncryptedStringExample.EncryptedString,
EncryptedStringExample">
    <!--定义加密类-->
    <param name="encryptor">
      EncryptedStringExample.DESEncryptor,
      EncryptedStringExample
    </param>
    <!--设置密钥-->
    <param name="encryptionKey">12345678</param>
  </typedef>
  <class name="Account">
    <id name="Id">
      <generator class="guid.comb" />
    </id>
    <property name="Name" not-null="true" />
    <property name="EMail" not-null="true" />
    <!--要加密的字段,注意设置了type="encrypted"-->
    <property name="CardNumber" not-null="true" type="encrypted"
/>
    <property name="ExpirationMonth" not-null="true" />
    <property name="ExpirationYear" not-null="true" />
    <property name="ZipCode" not-null="true" />
  </class>
</hibernate-mapping>

 在一个新建的控制台应用程序中,我们新建一个Account对象来测试一下:

 private static void AddAccount(NHibernate.ISession session)
        {
            session.Save(new Account() { 
             CardNumber="45678",
             EMail="bb@qq.com",
             ExpirationMonth=12,
             ExpirationYear=2012,
             Name="gyoung",
             ZipCode="55555"
            });
        }

加密的字段为:CardNumber.打开数据库,看到存储在其中的字段已经被加密了.

现在我们从数据库中取出该字段看看。因为只有一条记录,我就只取第一条了。

  private static Account GetAccount(NHibernate.ISession session)
        {
            return session.QueryOver<Account>().Take(1).SingleOrDefault();
        }

在Main方法中增加两行代码:

  Account account = GetAccount(session);
  Console.WriteLine(account.CardNumber);

我们可以看到控制台上显示出来的值为:

 可以看出解密正确。

 源码下载:点我。项目中的EncryptedStringExample与EncryptedStringTest

 

 

 

 

posted @ 2012-05-28 00:07  Gyoung  阅读(1616)  评论(6编辑  收藏  举报