Лучший способ создать хэш-подпись (HMAC) для объектов XMLSerialized в .NET - PullRequest
2 голосов
/ 26 октября 2009

Мне нужно сгенерировать HMAC для объектов, которые я сериализирую, используя XMLSerializer, найденный в .NET Framework. Каждый объект будет содержать свойство с именем «HMAC», которое будет содержать сам хэш значений объекта, но исключая поле «HMAC». Я нашел этот вопрос , в котором упоминается встроенное решение в CLR, но не уточняется, как он называется, или как мне его использовать?

Пример объекта будет выглядеть примерно так:

[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;
    }
}

Свойство HMAC необходимо установить как сериализацию всего объекта, за исключением самого объекта HMAC. Мои первые мысли о настройке своего рода двухпроходной сериализации, которая включает в себя:

  1. Установка свойства xmlignore для объекта HMAC при первом проходе
  2. Сериализация всего объекта
  3. Хеширование результата и установка значения свойства HMAC
  4. Повторно сериализовать все это снова, готово к передаче.

Это лучший способ сделать это? Кто-нибудь делал что-то подобное раньше и что вы считаете самым чистым способом сделать это ???

1 Ответ

2 голосов
/ 31 октября 2009

Я думаю, вам придется сериализовать его дважды, чтобы получить именно тот эффект, который вы описали. Одним из способов сделать это проще было бы не использовать XmlIgnore, а вместо этого добавить общедоступное указанное свойство (которое сериализация .NET XML обрабатывает специально для программного контроля, следует ли отправлять одноименное свойство):

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

То, что это будет делать, это испускать hmac узел XML, только если он существует. Подобный эффект может быть достигнут с DefaultValueAttribute, но я обнаружил некоторые несоответствия с ним (например, null иногда заменяется на "" во время компиляции). Кроме того, если бы ваша логика была более сложной, чем одиночное постоянное значение, вы могли бы обрабатывать это в свойстве, но не в статическом атрибуте.

get { return !this.IsCalculatingHmac(); }

Я бы поступил так, если бы формат точно совпадал с тем, что вы описали.


Если у вас есть гибкость в формате вывода, другой подход, который вы могли бы рассмотреть, - это наличие контейнера сообщений, который содержит тело сообщения (ваш текущий документ XML) и значение подписи HMAC. Таким образом, вам нужно будет только сериализовать документ один раз.

Даже если конверт был частью большого сериализационного документа, вы могли бы реализовать интерфейс IXmlSerializable.WriteXml на конверте. Это позволит вам аккуратно сериализовать сообщение в строку, затем выполнить хеш, а затем записать HMAC и элементы сообщения в одном через XmlWriter.WriteRaw.

Так бы я поступил, если бы производительность была важна.

...