2014-01-08 46 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

確實如此,但它們只需要一個密鑰指紋(密鑰的散列)與接收的指紋進行比較。 –

相關問題