I’m in the process of working on a Smart Client application that works with Business Objects. All Business Objects implement the following interface:
public interface IBusinessObject
{
int ID { get; }
byte[] Signature { get; set; }
byte[] ConcurrencyCheck { get; }
// Other properties here
}
As you can see, each BO has a unique ID integer associated with it. This value is used for many things. I want to ensure that a malicious user can not modify this value and present the hacked BO to the server. To verify the integrity of the BO I decided to digitally sign it using the value of the ID property. This can be done with the following code:
public static void Sign(IBusinessObject instance)
{
Sign(instance, instance.ID);
}
public static void Sign(IBusinessObject instance, int id)
{
if (instance == null)
throw new ArgumentNullException("instance");
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(BitConverter.GetBytes(id));
DSASignatureFormatter DSAFormatter = new DSASignatureFormatter(DSAProvider);
DSAFormatter.SetHashAlgorithm("SHA1");
instance.Signature = DSAFormatter.CreateSignature(hash);
}
public const int ExpectedSignatureLength = 40;
public static bool IsValid(IBusinessObject instance)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (instance.Signature == null || instance.Signature.Length != ExpectedSignatureLength)
return false;
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hash = sha.ComputeHash(BitConverter.GetBytes(instance.ID));
DSASignatureDeformatter DSADeformatter = new DSASignatureDeformatter(DSAProvider);
return DSADeformatter.VerifySignature(hash, instance.Signature);
}
The nice thing is that the DSASignatureFormatter class will automatically salt the generated signature. It is important to note that the “DSAProvider” variable above be a static variable within the class. This is needed in order to ensure that it is loaded with a constant key value so that, when a BO is verified at some point in the future, the check will succeed for previously issued signatures. I accomplish this by loading the key using the “FromXmlString” method in the static constructor for the host class:
public static readonly DSACryptoServiceProvider DSAProvider;
static SecurityHelper()
{
DSAProvider = new DSACryptoServiceProvider();
DSAProvider.FromXmlString(KeySet); // Value obtained from ToXmlString
}