2

我需要为使用 .NET 框架中的 XMLSerializer 序列化的对象生成 HMAC。每个对象都将包含一个名为“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. 重新序列化整个事情,准备传输。

这是最好的方法吗?以前有没有人做过这样的事情,你发现什么是最干净的方法???

4

1 回答 1

2

我认为您必须将其序列化两次才能获得您描述的确切效果。使这更容易的一种方法是不使用 XmlIgnore 而是添加一个公共指定属性(.NET XML 序列化特别对待它以编程方式控制是否发出类似命名的属性):

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

这将只在hmac存在 XML 节点时发出 XML 节点。可以达到类似的效果,DefaultValueAttribute但我发现它有些不一致(例如,有时在编译期间null被替换为)。""另外,如果您的逻辑比单个 contant sentinel 值更复杂,您可以在属性中处理它,但不能在静态属性中处理。

get { return !this.IsCalculatingHmac(); }

如果格式必须与您所描述的完全匹配,这就是我会这样做的方式。


如果您在输出格式上有灵活性,您可能会考虑使用包含消息正文(您当前的 XML 文档)和 HMAC 签名值的消息容器。这样,您只需序列化文档一次。

即使信封是更大的序列化文档的一部分,您也可以IXmlSerializable.WriteXml在信封上实现接口。这将允许您仔细地将消息序列化为字符串,然后执行散列,然后通过XmlWriter.WriteRaw.

如果性能很重要,我会这样做。

于 2009-10-31T15:19:14.870 回答