2014-01-08 113 views
1

我已经看到几个类似的问题,但没有一个解决我所问的问题。SignedXml.CheckSignature只有在使用私钥进行验证时才会返回true

我想签署一个XML,然后使用C#验证它的公钥。

我用密钥对XML进行签名,然后将密钥导出到XML。然后将密钥和签名的XML带到另一台计算机,使用rsa.FromXmlString(doc.InnerXml)导入密钥,并验证XML签名。

如果我使用rsa.ToXmlString(True)将公钥和私钥导出到XML,这将起作用。但是,我只想使用rsa.ToXmlString(False)导出我的公钥。如果我只导出公钥并将其导入第二台计算机,并尝试验证XML签名,则表示签名无效。

首先,我是否应该能够使用公钥验证签名的XML?第二,如果这是真的,那么为什么我的验证XML函数只能与pub/priv密钥对一起使用,而不能与只使用公钥?

你有什么关于如何调试这个问题的智慧?我不知道还有什么要做,因为signedXml.CheckSignature(Key);没有提供任何有关它失败原因的信息。

下面是我的导入密钥,导出密钥,签名XML和验证XML函数。如果您需要更多信息,请与我们联系。

public static void ImportKeyFromFile(string ContainerName, string inputFile) 
    { 
     try 
     { 
      // Create new XmlDocument. 
      XmlDocument doc = new XmlDocument(); 

      // Load XML Document. 
      doc.Load(inputFile); 

      // Create the CspParameters object and set the key container 
      // name used to store the RSA key pair. 
      CspParameters cp = new CspParameters(); 
      cp.KeyContainerName = ContainerName; 

      // Create a new instance of RSACryptoServiceProvider that accesses 
      // the key container MyKeyContainerName. 
      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp); 

      // Get RSA Parameters from xml document. 
      rsa.FromXmlString(doc.InnerXml); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 
    public static void ExportKeyToFile(string ContainerName, string outputPath, bool private_key) 
    { 
     try 
     { 
      // Create the CspParameters object and set the key container 
      // name used to store the RSA key pair. 
      CspParameters cp = new CspParameters(); 
      cp.KeyContainerName = ContainerName; 

      // Create a new instance of RSACryptoServiceProvider that accesses 
      // the key container MyKeyContainerName. 
      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp); 

      // Create new XmlDocument. 
      XmlDocument doc = new XmlDocument(); 

      // Store rsa key. 
      doc.InnerXml = rsa.ToXmlString(private_key); 

      // Save Document. 
      doc.Save(outputPath); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 
    public static Boolean VerifyXml(XmlDocument Doc, RSA Key) 
    { 
     // Check arguments. 
     if (Doc == null) 
      throw new ArgumentException("Doc"); 
     if (Key == null) 
      throw new ArgumentException("Key"); 

     // Create a new SignedXml object and pass it 
     // the XML document class. 
     SignedXml signedXml = new SignedXml(Doc); 

     // Find the "Signature" node and create a new 
     // XmlNodeList object. 
     XmlNodeList nodeList = Doc.GetElementsByTagName("Signature"); 

     // Throw an exception if no signature was found. 
     if (nodeList.Count <= 0) 
     { 
      throw new CryptographicException("Verification failed: No Signature was found in the document."); 
     } 

     // Load the first <signature> node. 
     signedXml.LoadXml((XmlElement)nodeList[0]); 

     // Check the signature and return the result. 
     return signedXml.CheckSignature(Key); 
    } 
    public static void SignXml(XmlDocument xmlDoc, RSA Key) 
    { 
     // Check arguments. 
     if (xmlDoc == null) 
      throw new ArgumentException("xmlDoc"); 
     if (Key == null) 
      throw new ArgumentException("Key"); 

     // Create a SignedXml object. 
     SignedXml signedXml = new SignedXml(xmlDoc); 

     // Add the key to the SignedXml document. 
     signedXml.SigningKey = Key; 

     // Create a reference to be signed. 
     Reference reference = new Reference(); 
     reference.Uri = ""; 

     // Add an enveloped transformation to the reference. 
     XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); 
     reference.AddTransform(env); 

     // Add the reference to the SignedXml object. 
     signedXml.AddReference(reference); 

     // Compute the signature. 
     signedXml.ComputeSignature(); 

     // Get the XML representation of the signature and save 
     // it to an XmlElement object. 
     XmlElement xmlDigitalSignature = signedXml.GetXml(); 

     // Append the element to the XML document. 
     xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); 
    } 

回答

1

问题是因为您不能将公钥存储在密钥容器中。要使用公钥验证签名,您应该使用rsa.FromXmlString从XML中导入密钥,然后直接将rsa传递给Verify Signature函数。如果您尝试将公钥存储在密钥容器中并在稍后检索,则最终只会创建一个新密钥。 How to store a public key in a machine-level RSA key container

+0

另一种选择将是包括签署文档中键(或者甚至是证书)。这并不占用太多空间,但可以减轻消费者从单独渠道获取钥匙的难度。 –

+0

消费者仍然需要一些如何检查公钥是否属于她认为是的。就我而言,当xml被接收时,消费者已经拥有了公钥。 – user985637

+0

确实如此,但它们只需要一个密钥指纹(密钥的散列)与接收的指纹进行比较。 –

相关问题