views:

222

answers:

1

I need to generate a HMAC for objects that I am serializing using the XMLSerializer found in the .NET framework. Each object will contain a property called "HMAC" that will contain a hash of the object's values itself but excluding the "HMAC" field. I've found this question that mentions a built-in solution within the CLR but doesn't elaborate on exactly what its called or how I go about using it?

A sample object would look something like this:

[Serializable]
[XmlRoot("request", IsNullable = false)]
public class Request
{

 [XmlElement(ElementName = "hmac")]
 public string Hmac { get; set; } 

 [XmlElement(ElementName = "nonce")]
 public string Nonce { get; set; }

 [XmlElement(ElementName = "expiration")]
 public DateTime Expiration { get; set; }

    /* A bunch of other properties to be serialized */

 private Request() { }

 public Request(string hmac, string nonce, DateTime expiration)
 {
  Hmac = hmac;
  Nonce = nonce;
  Expiration = expiration;
 }
}

The HMAC property will need to be set as a serialization of the entire object, excluding the HMAC object itself. My first thoughts are setting up some sort of two-pass serialization, which involves:

  1. Setting an xmlignore property to the HMAC object on the first pass
  2. Serializing the entire object
  3. Hashing the result, and setting the value of the HMAC property
  4. Re-serializing the whole thing again, ready for transmission.

Is this the best way to go about it? Has anyone done anything like this before, and what have you found to be the cleanest way of going about it???

+2  A: 

I think you will have to serialize it twice to get the exact effect you described. One way to make that easier would be to not use XmlIgnore but instead add a public specified property (which .NET XML serialization treats specially to programmatically control whether to emit the similarly named property):

 [XmlIgnore]
 public bool HmacSpecified
 {
     get { return !String.IsNullOrEmpty(this.Hmac); }
     set { }
 }

What this will do is only emit the hmac XML node if one exists. A similar effect could be achieved with the DefaultValueAttribute but I've found some inconsistencies with it (e.g. null is sometimes replaced with "" during compilation). Plus if your logic was more complex than a single contant sentinel value you could handle that in the property but not in a static attribute.

get { return !this.IsCalculatingHmac(); }

This would be the way I would do it if the format had to exactly match what you've described.


If you have flexibility in the output format, another approach you might consider is having a message container which contains the message body (your current XML doc) and an HMAC Signature value. This way you would only need to serialize the document once.

Even if the envelope were part of a larger serialization document you could implement an IXmlSerializable.WriteXml interface on the envelope. This would allow you to carefully serialize the message to a string, then perform the hash, then write out the HMAC and message elements all in one via XmlWriter.WriteRaw.

This would be the way I would do it if performance was important.

McKAMEY
The "envelope" approach is the better one. The envelope idea is fundamental in SOAP, of course.
Cheeso