Creating Signed SOAP Message as a String with C#

那年仲夏 提交于 2019-12-04 13:49:56
  1. For the DigestValue you need to you need to canonicalize a string like this:
   <u:Timestamp u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
              <u:Created>2016-06-14T22:56:10.896Z</u:Created>
              <u:Expires>2016-06-14T23:01:10.896Z</u:Expires>
          </u:Timestamp>

So you can just put that string as a parameter here:

private string CanonicalizeDsig(string input)
{
    XmlDocument doc = new XmlDocument();
    doc.PreserveWhitespace = false;
    try
    {
        doc.LoadXml(input);
        XmlDsigC14NTransform trans = new XmlDsigC14NTransform();
        trans.LoadInput(doc);
        String c14NInput = new StreamReader((Stream)trans.GetOutput(typeof(Stream))).ReadToEnd();

        return c14NInput;


    }
    catch (Exception ex)
    {
        return String.Empty;
    }

}

After canonicalization you can now compute for the Hash: (mine is a SHA1 example). So put the return value of the above method on the parameter of this one. to get something like JCMdwz5g8iq05Lj6tjfDOxKqT4k=

private string ComputeHashSHA1(string input)
{
    try
    {
        SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
        byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(input));
        string digestValue = Convert.ToBase64String(hashedDataBytes);
        return digestValue;

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
        return String.Empty;
    }

}
  1. The Signature value is a tricky one and I can only cover a specific example. Check the service's WSDL it if has a policy that looks something like this.
<sp:Trust10> <wsp:Policy> <sp:MustSupportIssuedTokens/> <sp:RequireClientEntropy/> <sp:RequireServerEntropy/> </wsp:Policy>

This means you need to combine the Client Entropy (which is your key - any string that is based 64 that you sent to the server on get token request) and the Server Entropy (the return base 64 key)

You can combine them using the Microsoft.IdentityModel dll where there is a KeyGenerator object.

Your input will be something like this and it also needs canonicalization with DsigExcC14N:

              <SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
              <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
              <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
              <Reference URI="#_0">
                  <Transforms>
                      <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                  </Transforms>
                  <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                  <DigestValue>JCMdwz5g8iq05Lj6tjfDOxKqT4k=</DigestValue>
              </Reference>
          </SignedInfo>

Here is the canonicalization:

private string CanonicalizeExc(string input)
{
    XmlDocument doc = new XmlDocument();
    doc.PreserveWhitespace = false;
    try
    {
        doc.LoadXml(input);
        XmlDsigExcC14NTransform trans = new XmlDsigExcC14NTransform();
        trans.LoadInput(doc);
        String c14NInput = new StreamReader((Stream)trans.GetOutput(typeof(Stream))).ReadToEnd();

        return c14NInput;


    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
        return String.Empty;
    }

}

Then here is how you get the signature value:

        private string ComputeHMACSHA1_PSHA(string input, string serversecret, string clientsecret)
    {
        try
        {
            byte[] signedInfoBytes = Encoding.UTF8.GetBytes(input);

            byte[] binarySecretBytesServer = Convert.FromBase64String(serversecret);
            byte[] binarySecretBytesClient = Convert.FromBase64String(clientsecret);

            byte[] key = KeyGenerator.ComputeCombinedKey(binarySecretBytesClient, binarySecretBytesServer, 256);


            HMACSHA1 hmac = new HMACSHA1(key);
            hmac.Initialize();

            byte[] hmacHash = hmac.ComputeHash(signedInfoBytes);
            string signatureValue = Convert.ToBase64String(hmacHash);
            return signatureValue;
        }
        catch (Exception ex)
        {
            return string.Empty;
        }
    }

It will give you something like this. kykmlowWIW4TXRcCi46OfZPUBKQ=

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!