With the industry moving away from SHA1 including Microsoft (see http://social.technet.microsoft.com/wiki/contents/articles/32288.windows-enforcement-of-authenticode-code-signing-and-timestamping.aspx), many developers should start using SHA2 in their code. There are resources on the internet that describe how to use SHA256 with SignedXml. This blog is meant to summarize it in one place.
First of all, we need to register a SignatureDescription class that defines the DigestAlgorithm as SHA256. The .NET Cryptography namespace implements a class called RSAPKCS1SHA1SignatureDescription that supports SHA1. So we need a similar class called RSAPKCS1SHA256SignatureDescription that supports SHA256.
If your code is based on .NET 4.5 or higher, there is an RSAPKCS1SHA256SignatureDescription class you can register. You have to reference the System.Deployment assembly in your project. The full namespace is System.Deployment.Internal.CodeSigning.RSAPKCS1SHA256SignatureDescription. You must call CryptoConfig.AddAlgorithm to register the class.
Here’s the MSDN SignedXml sample modified to use SHA256:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
using System.Deployment.Internal.CodeSigning;
{
public class SignVerifyEnvelope
{
public static void Main(String[] args)
{
try
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), “http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″);
// Generate a signing key.
RSACryptoServiceProvider Key = new RSACryptoServiceProvider();
CreateSomeXml(“Example.xml”);
Console.WriteLine(“New XML file created.”);
// new file.
SignXmlFile(“Example.xml”, “signedExample.xml”, Key);
Console.WriteLine(“XML file signed.”);
Console.WriteLine(“Verifying signature…”);
bool result = VerifyXmlFile(“SignedExample.xml”, Key);
// the console.
if (result)
{
Console.WriteLine(“The XML signature is valid.”);
}
else
{
Console.WriteLine(“The XML signature is not valid.”);
}
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
}
}
// save the public key within the XML file. This file cannot be verified unless
// the verifying code has the key with which it was signed.
public static void SignXmlFile(string FileName, string SignedFileName, RSA Key)
{
// Create a new XML document.
XmlDocument doc = new XmlDocument();
doc.Load(new XmlTextReader(FileName));
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = Key;
signedXml.SignedInfo.SignatureMethod = “http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″;
Reference reference = new Reference();
reference.Uri = “”;
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.DigestMethod = “http://www.w3.org/2001/04/xmlenc#sha256″;
signedXml.AddReference(reference);
signedXml.ComputeSignature();
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
{
doc.RemoveChild(doc.FirstChild);
}
// using the passed string.
XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false));
doc.WriteTo(xmltw);
xmltw.Close();
}
// algorithm and return the result.
public static Boolean VerifyXmlFile(String Name, RSA Key)
{
// Create a new XML document.
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(Name);
// the XML document class.
SignedXml signedXml = new SignedXml(xmlDocument);
// XmlNodeList object.
XmlNodeList nodeList = xmlDocument.GetElementsByTagName(“Signature”);
signedXml.LoadXml((XmlElement)nodeList[0]);
return signedXml.CheckSignature(Key);
}
public static void CreateSomeXml(string FileName)
{
// Create a new XmlDocument object.
XmlDocument document = new XmlDocument();
XmlNode node = document.CreateNode(XmlNodeType.Element, “”, “MyElement”, “samples”);
node.InnerText = “Example text to be signed.”;
document.AppendChild(node);
XmlTextWriter xmltw = new XmlTextWriter(FileName, new UTF8Encoding(false));
document.WriteTo(xmltw);
xmltw.Close();
}
}