random .NET and web development musings

The simplest way I’ve found to encrypt data with NHibernate is to use a custom UserType which encrypts/decrypts the data on read/write.

As this post on stackoverflow demonstrates, it’s rather easy to make such a UserType. However, what I didn’t want to have to do is make a different UserType for each different property type that I want to encrypt.

Enter Encrypted<T>:

public class Encrypted<T> : PrimitiveType
{
	private readonly IEncryptionService encrypter;
	private readonly IBinaryConverter converter;

	public Encrypted() : base(new BinarySqlType())
	{
		this.encrypter = ServiceLocator.Current.GetInstance<IEncryptionService>();
		this.converter = ServiceLocator.Current.GetInstance<IBinaryConverter>();
	}

	public override string Name
	{
		get { return typeof (T).Name; }
	}

	public override Type ReturnedClass
	{
		get { return typeof (T); }
	}

	public override Type PrimitiveClass
	{
		get { return typeof (T); }
	}

	public override object DefaultValue
	{
		get { return default(T); }
	}

	public override void Set(IDbCommand cmd, object value, int index)
	{
		var serialized = this.converter.Serialize(value);
		var encrypted = this.encrypter.Encrypt(serialized);

		((IDataParameter) cmd.Parameters[index]).Value = encrypted;
	}

	public override object Get(IDataReader rs, int index)
	{
		if (rs.IsDBNull(index))
			return null;

		var encrypted = rs[index] as byte[];

		var decrypted = this.encrypter.Decrypt(encrypted);
		var deserialized = this.converter.Deserialize(decrypted);

		return deserialized;
	}

	public override object Get(IDataReader rs, string name)
	{
		return this.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 (var i = 0; i < bytes.Length; i++)
		{
			var hexStr = xml.Substring(i * 2, (i + 1) * 2);
			bytes[i] = (byte) (byte.MinValue + byte.Parse(hexStr, NumberStyles.HexNumber, CultureInfo.InvariantCulture));
		}

		var decrypted = this.encrypter.Decrypt(bytes);
		var deserialized = this.converter.Deserialize(decrypted);

		return deserialized;
	}

	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();
	}
}

The implementations of IBinaryConverter and IEncryptionService aren’t important for the purposes of this post, here are their signatures so you can implement then how you like:

public interface IBinaryConverter
{
	byte[] Serialize(object obj);
	object Deserialize(byte[] bytes);
}

public interface IEncryptionService
{
	byte[] Encrypt(byte[] plain);
	byte[] Decrypt(byte[] cipher);
}

There are plenty of discussions on why you should do this, which I’m not going to cover here.

What I am interested in discussing is a solution to the endless overriding of Equals and GetHashCode in each of your entities. Not only does this pollute the object with noise, but its a nightmare to maintain.

I use GUIDs for my Id columns, which is very convenient as you don’t have to goto the database for clues as to what the next unique ID may be.

Normally, when overriding GetHashCode you have to compare all your entity’s properties and when comparing for equality, you have to do the same because transient objects don’t yet have an ID.

This got me thinking, why even bother letting NH assign the ID? If you create the ID in your entities’ constructor GetHashCode and Equals become very easily overridden and can be abstracted to a base class, like so:

public abstract class Entity
{
	public virtual Guid Id { get; protected set; }

	protected Entity()
	{
		this.Id = Guid.NewGuid();
	}

	public override int GetHashCode()
	{
		return this.Id.GetHashCode();
	}

	public override bool Equals(object obj)
	{
		if (ReferenceEquals(this, obj))
			return true;

		var entity = obj as Entity;
		if (ReferenceEquals(null, entity))
			return false;

		return entity.Id.Equals(this.Id);
	}
}

For this to work, you must set your NHibernate ID Generator mapping to “Assigned”, like so:

<id name="Id" type="System.Guid">
    <column name="Id" />
    <generator class="assigned" />
</id>

For all you optimizers out there, you can still use alternate GUID algorithms like Comb :)

Thoughts?

If you need to get access to the date part of a DateTime through HQL, the easiest way is to use a custom dialect:

public class CustomDialect : SQLiteDialect
{
	public CustomDialect()
	{
		RegisterFunction("DateOnly", new StandardSQLFunction("date", NHibernateUtil.String));
	}
}

public class CustomDialect : MsSql2005Dialect
{
	public CustomDialect()
	{
		RegisterFunction("DateOnly", new SQLFunctionTemplate(NHibernateUtil.DateTime, "DATEADD(dd, 0, DATEDIFF(dd, 0, ?1))"));
	}
}

Because I use SQLite for my integration tests and MSSQL2005 for my runtime database, I need two different dialects, one for each provider. Using the custom function name “DateOnly” I can have the same HQL work on both databases 😀

You can then use this function, like so:

select DateOnly(x.Date), count(x.Id)
from someEntity x
group by DateOnly(x.Date)

Win.