如何在C#中手动计算XML签名

Mar*_*inK 5 c# xml soap

我知道有一个用于签名XML文档的SignedXml类。但是,我试图自己计算签名值,以了解发生了什么。更确切地说,我正在尝试签署SOAP消息的soap:Body元素。我已经手动创建了Signature标签,使其与模板匹配。另外,我已经成功计算了摘要,并将此值插入DigestValue标记中。但是,我无法为SigantureValue标签计算正确的值。

我的方法是:

  1. 使用excl n14n转换规范化SignedInfo标签
  2. 使用SHA256哈希规范化的数据
  3. 使用RSACryptoServiceProvider签名哈希值

我的代码如下所示:

  // 1 Canonicalize the SignedInfo tag 
  XmlDsigExcC14NTransform serializer = new XmlDsigExcC14NTransform();
  XmlDocument doc = new XmlDocument();
  string toBeCanonicalized = signedInfoTag.OuterXml;
  doc.LoadXml(toBeCanonicalized);
  serializer.LoadInput(doc);
  string c14n = new StreamReader((Stream)serializer.GetOutput(typeof(Stream))).ReadToEnd();

  // 2 Hash the SignedInfo tag

  SHA256 HashAlg = SHA256.Create();
  byte[] hash = HashAlg.ComputeHash(Encoding.UTF8.GetBytes(c14n));

  // 3 Sign the hash

  byte[] signature;
  using (RSACryptoServiceProvider csp = new RSACryptoServiceProvider())
  {
    csp.ImportParameters(((RSACryptoServiceProvider)mCertificate.PrivateKey).ExportParameters(true));
    signature = csp.SignData(Encoding.UTF8.GetBytes(c14n), "SHA256");
  }
  signValueTag.InnerText = Convert.ToBase64String(signature);
Run Code Online (Sandbox Code Playgroud)

我做错了什么?

有效SOAP消息的示例在这里:

  // 1 Canonicalize the SignedInfo tag 
  XmlDsigExcC14NTransform serializer = new XmlDsigExcC14NTransform();
  XmlDocument doc = new XmlDocument();
  string toBeCanonicalized = signedInfoTag.OuterXml;
  doc.LoadXml(toBeCanonicalized);
  serializer.LoadInput(doc);
  string c14n = new StreamReader((Stream)serializer.GetOutput(typeof(Stream))).ReadToEnd();

  // 2 Hash the SignedInfo tag

  SHA256 HashAlg = SHA256.Create();
  byte[] hash = HashAlg.ComputeHash(Encoding.UTF8.GetBytes(c14n));

  // 3 Sign the hash

  byte[] signature;
  using (RSACryptoServiceProvider csp = new RSACryptoServiceProvider())
  {
    csp.ImportParameters(((RSACryptoServiceProvider)mCertificate.PrivateKey).ExportParameters(true));
    signature = csp.SignData(Encoding.UTF8.GetBytes(c14n), "SHA256");
  }
  signValueTag.InnerText = Convert.ToBase64String(signature);
Run Code Online (Sandbox Code Playgroud)

Ano*_*mys 1

尝试使用

string toBeCanonicalized = signedInfoTag.InnerXml;
Run Code Online (Sandbox Code Playgroud)

代替

string toBeCanonicalized = signedInfoTag.OuterXml;
Run Code Online (Sandbox Code Playgroud)

完整代码:

// 1 Canonicalize the SignedInfo tag 
XmlDsigExcC14NTransform serializer = new XmlDsigExcC14NTransform();
XmlDocument doc = new XmlDocument();
string toBeCanonicalized = signedInfoTag.InnerXml;
doc.LoadXml(toBeCanonicalized);
serializer.LoadInput(doc);
string c14n = new StreamReader((Stream)serializer.GetOutput(typeof(Stream))).ReadToEnd();

// 2 Hash the SignedInfo tag
SHA256 HashAlg = SHA256.Create();
byte[] hash = HashAlg.ComputeHash(Encoding.UTF8.GetBytes(c14n));

// 3 Sign the hash
byte[] signature;
using (RSACryptoServiceProvider csp = new RSACryptoServiceProvider())
{
    csp.ImportParameters(((RSACryptoServiceProvider)mCertificate.PrivateKey)
       .ExportParameters(true));
    signature = csp.SignData(Encoding.UTF8.GetBytes(c14n), "SHA256");
}
signValueTag.InnerText = Convert.ToBase64String(signature);
Run Code Online (Sandbox Code Playgroud)