为数据库中的关键字段进行加密是必不可少的,特别是一些用户密码,银行卡账号等。现在我们来说一下如何在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
© 2022-2023 Fengnayun.com 版权所有 | 沪ICP备2022019637号-1 | 51LA统计
增值电信业务经营许可证:B1-20223846 | 黔作登字-2022-F-00488892
代理域名注册服务机构:成都西维数码科技有限公司 | 部分地域产品合作单位:云南悍铭科技有限公司