2009-10-26 49 views
2

我需要为使用.NET框架中找到的XMLSerializer序列化的对象生成一个HMAC。每个对象将包含一个名为“HMAC”的属性,该属性将包含该对象的值本身的散列,但不包括“HMAC”字段。我发现this question提到了CLR中的内置解决方案,但没有详细说明它的名称或使用方法。在.NET中为XMLSerialized对象生成哈希签名(HMAC)的最佳方法?

样本对象会是这个样子:

[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. 第一遍
  2. 序列化整个对象
  3. 哈希结果设定一个xmlignore属性设置为HMAC对象,设置HMAC属性的值
  4. 重新序列化整个事情,准备传输。

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

回答

2

我想你将不得不连续两次得到你描述的确切效果。

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

这将完成:为了更轻松地将不使用XmlIgnore而是将一个公共的指定属性(.NET XML序列化对待专门编程控制是否发出类似命名的特性)的一种方法仅存在hmac XML节点(如果存在)。 DefaultValueAttribute也可以达到类似的效果,但我发现它有一些不一致之处(例如null在编译过程中有时被替换为"")。此外,如果您的逻辑比单个定位标记值更复杂,您可以在属性中处理它,但不能处理静态属性。

get { return !this.IsCalculatingHmac(); } 

这将是我会这样做,如果格式必须完全符合你所描述的方式。


如果您在输出格式的灵活性,你可以考虑在具有包含邮件正文的消息容器(当前的XML文档)和HMAC签名值的另一种方法。这样你只需要序列化一次文档。

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

如果表现很重要,我会这样做。

+0

“信封”方法是更好的方法。当然,信封想法在SOAP中很重要。 – Cheeso 2009-11-26 16:03:22