2012-08-31 71 views
5

Có cách nào để ký một tệp XML với RSA và có tiền tố không gian tên "ds: Chữ ký" thay vì "Chữ ký" không? Tôi đã dành nhiều giờ để giải quyết điều này và từ những gì tôi có thể thấy không có giải pháp.Tiền tố DS chữ ký xml?

Có vẻ như nó được mã hóa cứng trong lớp System.Security.Cryptography.Xml.Signature.

XmlElement element = document.CreateElement("Signature", "http://www.w3.org/2000/09/xmldsig#"); 

Nếu có ai biết một giải pháp, tôi cần phải đăng ký nó như thế làm cho phần mềm nhập khẩu nó kiểm tra nó với "ds: chữ ký", như vậy với "ds" tiền tố phần mềm kiểm tra nó như thế này:

public static bool VerifySignature(XmlDocument doc, RSA key, string prefix) 
    { 
     SignedXml xml = new SignedXml(doc); 
     string str = "Signature"; 
     if (!string.IsNullOrEmpty(prefix)) 
     { 
      str = string.Format("{0}:{1}", prefix, str); 
     } 
     XmlNodeList elementsByTagName = doc.GetElementsByTagName(str); 
     xml.LoadXml((XmlElement)elementsByTagName[0]); 
     return xml.CheckSignature(key); 
    } 

    VerifySignature(xmlDoc, rsa, "ds"); 

thường nó có dấu hiệu như thế này:

<kk>blabla<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>rVL2nKjPTBhL9IDHYpu69OiE8gI=</DigestValue></Reference></SignedInfo><SignatureValue>CfXW9D/ErmHjzxIjy0/54/V3nst6j/XXcu7keR17LApfOZEpxjEvAlG3VnBZIi3jxQzU6t9RkmfDyngcRZccJByuuA6YDwFTQxZNRgu2GRoZxMKWnkm+MtQ0jH0Fo78GivCxV+iIewZvsrUQLzG01cXuZSH/k2eeMUaEooJaLQiYpO2aNVn5xbosTPtGlsACzFWz34E69/ZeeLZbXLc3jpDO+opxdYJ5e+Tnk/UM2Klt+N+m7Gh/sUNTPgkDiwP3q3y3O9tvCT0G2XmQaWBP4rw9TIoYHQtucm2b8R2JeggbeRKOetbRYV218RT8CK2Yuy0FIUlQXdabKyp9F96Yc55g8eNe10FGtgietH2iqquIVFLCA8fu3SZNLDPMoyHnVNKdBvI35+S8hrAaybEkMvo7iYnUSY5KrlGSfGGtfQXdaISutAzcnGPDFXgZXPNzNy7eL0u+Lt3yWWkj7wh6Zeh4fH2+nXDWYCWbLpegAEX4ZWSI5Ts6D1TplMJTGH1F0GyflehH4u+W4Lc3TvkB4dWjEuiKgnpl3hcvoj2CWFaeAxXMd/64tU/YMm8+1gSBjkVH6oV+QlI/m0z6M8FPVEVC2as0wLG2woVwmzVLcaQKyPi7NN4eO9ea7QNfaRHaofU4LQO/Y3FNJOP+uMfYlGJKWSr3qv29+BQjeNldNJY=</SignatureValue></Signature></kk> 

và tôi cần nó để làm điều đó như thế này:

<kk>blabla<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><ds:DigestValue>rVL2nKjPTBhL9IDHYpu69OiE8gI=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>CfXW9D/ErmHjzxIjy0/54/V3nst6j/XXcu7keR17LApfOZEpxjEvAlG3VnBZIi3jxQzU6t9RkmfDyngcRZccJByuuA6YDwFTQxZNRgu2GRoZxMKWnkm+MtQ0jH0Fo78GivCxV+iIewZvsrUQLzG01cXuZSH/k2eeMUaEooJaLQiYpO2aNVn5xbosTPtGlsACzFWz34E69/ZeeLZbXLc3jpDO+opxdYJ5e+Tnk/UM2Klt+N+m7Gh/sUNTPgkDiwP3q3y3O9tvCT0G2XmQaWBP4rw9TIoYHQtucm2b8R2JeggbeRKOetbRYV218RT8CK2Yuy0FIUlQXdabKyp9F96Yc55g8eNe10FGtgietH2iqquIVFLCA8fu3SZNLDPMoyHnVNKdBvI35+S8hrAaybEkMvo7iYnUSY5KrlGSfGGtfQXdaISutAzcnGPDFXgZXPNzNy7eL0u+Lt3yWWkj7wh6Zeh4fH2+nXDWYCWbLpegAEX4ZWSI5Ts6D1TplMJTGH1F0GyflehH4u+W4Lc3TvkB4dWjEuiKgnpl3hcvoj2CWFaeAxXMd/64tU/YMm8+1gSBjkVH6oV+QlI/m0z6M8FPVEVC2as0wLG2woVwmzVLcaQKyPi7NN4eO9ea7QNfaRHaofU4LQO/Y3FNJOP+uMfYlGJKWSr3qv29+BQjeNldNJY=</ds:SignatureValue></ds:Signature></kk> 
+0

Bạn không thể sửa đổi nội dung DOM XML sau khi ký tất cả mọi thứ và kết hợp nó thành một cây DOM? –

+1

nếu bạn sửa đổi bất kỳ nội dung xml nào sau khi ký signaturevalue sẽ không khớp ... –

+0

điểm là sửa đổi nút chữ ký, không phải nút đã ký. –

Trả lời

8

nếu có ai biết một giải pháp, tôi cần phải đăng ký nó như thế làm cho phần mềm nhập khẩu nó kiểm tra nó với "ds: chữ ký", như vậy với "ds" tiền tố

Tiền tố nên không quan trọng - tất cả những gì cần quan trọng là không gian tên phần tử nằm trong đó. Nó không quan trọng cách không gian tên đó được thể hiện. Nếu có, điều đó cho thấy sự hư hỏng trong mã xác minh, tôi muốn nói.

Tuy nhiên, nếu bạn thực sự là muốn làm điều này, có lý do nào bạn không muốn chỉ thay thế phần tử bằng một nội dung có cùng nội dung không, nhưng sử dụng tiền tố bạn muốn? Nó không phải là khó khăn để làm điều đó trong LINQ to XML.

+2

tôi đã chỉnh sửa bài đăng đầu tiên để xem cách phần mềm nhận XML xác minh ..., bạn không thể thay thế tiền tố của phần tử, vì sau đó ký hiệu sẽ khác ... –

7

tôi tìm thấy giải pháp here

using System; 
using System.Reflection; 
using System.Security.Cryptography.Xml; 
using System.Security.Cryptography; 
using System.Collections.Generic; 
using System.Text; 
using System.Xml; 

namespace mysign 
{ 
public class PrefixedSignedXML : SignedXml 
{ 
    public PrefixedSignedXML(XmlDocument document) 
     : base(document) 
    { } 

    public PrefixedSignedXML(XmlElement element) 
     : base(element) 
    { } 

    public PrefixedSignedXML() 
     : base() 
    { } 

    public void ComputeSignature(string prefix) 
    { 
     this.BuildDigestedReferences(); 
     AsymmetricAlgorithm signingKey = this.SigningKey; 
     if (signingKey == null) 
     { 
      throw new CryptographicException("Cryptography_Xml_LoadKeyFailed"); 
     } 
     if (this.SignedInfo.SignatureMethod == null) 
     { 
      if (!(signingKey is DSA)) 
      { 
       if (!(signingKey is RSA)) 
       { 
        throw new CryptographicException("Cryptography_Xml_CreatedKeyFailed"); 
       } 
       if (this.SignedInfo.SignatureMethod == null) 
       { 
        this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; 
       } 
      } 
      else 
      { 
       this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; 
      } 
     } 
     SignatureDescription description = CryptoConfig.CreateFromName(this.SignedInfo.SignatureMethod) as SignatureDescription; 
     if (description == null) 
     { 
      throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated"); 
     } 
     HashAlgorithm hash = description.CreateDigest(); 
     if (hash == null) 
     { 
      throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed"); 
     } 
     this.GetC14NDigest(hash, prefix); 
     this.m_signature.SignatureValue = description.CreateFormatter(signingKey).CreateSignature(hash); 
    } 

    public XmlElement GetXml(string prefix) 
    { 
     XmlElement e = this.GetXml(); 
     SetPrefix(prefix, e); 
     return e; 
    } 

    //Invocar por reflexión al método privado SignedXml.BuildDigestedReferences 
    private void BuildDigestedReferences() 
    { 
     Type t = typeof(SignedXml); 
     MethodInfo m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance); 
     m.Invoke(this, new object[] { }); 
    } 

    private byte[] GetC14NDigest(HashAlgorithm hash, string prefix) 
    { 
     //string securityUrl = (this.m_containingDocument == null) ? null : this.m_containingDocument.BaseURI; 
     //XmlResolver xmlResolver = new XmlSecureResolver(new XmlUrlResolver(), securityUrl); 
     XmlDocument document = new XmlDocument(); 
     document.PreserveWhitespace = true; 
     XmlElement e = this.SignedInfo.GetXml(); 
     document.AppendChild(document.ImportNode(e, true)); 
     //CanonicalXmlNodeList namespaces = (this.m_context == null) ? null : Utils.GetPropagatedAttributes(this.m_context); 
     //Utils.AddNamespaces(document.DocumentElement, namespaces); 

     Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject; 
     //canonicalizationMethodObject.Resolver = xmlResolver; 
     //canonicalizationMethodObject.BaseURI = securityUrl; 
     SetPrefix(prefix, document.DocumentElement); //establecemos el prefijo antes de se que calcule el hash (o de lo contrario la firma no será válida) 
     canonicalizationMethodObject.LoadInput(document); 
     return canonicalizationMethodObject.GetDigestedOutput(hash); 
    } 

    private void SetPrefix(string prefix, XmlNode node) 
    { 
     foreach (XmlNode n in node.ChildNodes) 
      SetPrefix(prefix, n); 
     node.Prefix = prefix; 
    } 
} 
} 
+0

điều này không có tác dụng đối với tôi, khối chữ ký đã kết thúc tăng tương tự mà không có tiền tố – tarrball

0

Có thể một cách chính xác SetPrefix mã trông như thế này:

private void SetPrefix(String prefix, XmlNode node) { 
     foreach (XmlNode n in node.ChildNodes) 
     { 
      SetPrefix(prefix, n); 
      n.Prefix = prefix; 
     } 
    } 
+0

bạn không hiểu câu hỏi. tôi đã cho sollution –

+1

@GeorgeDima Tôi đang chơi xung quanh với điều này, và sửa đổi khối chữ ký trong xml dường như không ảnh hưởng đến signatureValue. Vì vậy, nó sẽ được an toàn để làm điều này sau khi chữ ký đã được tạo ra.Bạn có chắc chắn rằng không làm việc cho bạn? –

+1

có, chỉ có giải pháp của tôi được đăng ở đây làm việc cho tôi, tôi có nghĩa là để có được nó xác minh. –

1

tôi đã cố gắng các giải pháp này, nhưng họ đã không làm việc ra. Tuy nhiên, bằng cách xem mã nguồn .NET (http://referencesource.microsoft.com/), chúng ta có thể thấy rằng điều này có thể được hoàn thành dễ dàng bằng cách cung cấp một lớp XmlDocument có nguồn gốc cho SignedXml, nơi mà không gian tên có thể được thêm vào. Tuy nhiên, có tiền tố "ds" trong 'SignedInfo' và con cháu sẽ khiến siganture thất bại. Dưới đây là tốt nhất tôi có thể làm mà không vi phạm chữ ký:


XmlDsigDocument.cs

using System; 
using System.Collections.Generic; 
using System.Security.Cryptography.Xml; 
using System.Text; 
using System.Xml; 

namespace CustomSecurity 
{ 
class XmlDsigDocument : XmlDocument 
{ 
    // Constants 
    public const string XmlDsigNamespacePrefix = "ds"; 

    /// <summary> 
    /// Override CreateElement function as it is extensively used by SignedXml 
    /// </summary> 
    /// <param name="prefix"></param> 
    /// <param name="localName"></param> 
    /// <param name="namespaceURI"></param> 
    /// <returns></returns> 
    public override XmlElement CreateElement(string prefix, string localName, string namespaceURI) 
    { 
     // CAntonio. If this is a Digital signature security element, add the prefix. 
     if (string.IsNullOrEmpty(prefix)) 
     { 
      // !!! Note: If you comment this line, you'll get a valid signed file! (but without ds prefix) 
      // !!! Note: If you uncomment this line, you'll get an invalid signed file! (with ds prefix within 'Signature' object) 
      //prefix = GetPrefix(namespaceURI); 

      // The only way to get a valid signed file is to prevent 'Prefix' on 'SignedInfo' and descendants. 
      List<string> SignedInfoAndDescendants = new List<string>(); 
      SignedInfoAndDescendants.Add("SignedInfo"); 
      SignedInfoAndDescendants.Add("CanonicalizationMethod"); 
      SignedInfoAndDescendants.Add("InclusiveNamespaces"); 
      SignedInfoAndDescendants.Add("SignatureMethod"); 
      SignedInfoAndDescendants.Add("Reference"); 
      SignedInfoAndDescendants.Add("Transforms"); 
      SignedInfoAndDescendants.Add("Transform"); 
      SignedInfoAndDescendants.Add("InclusiveNamespaces"); 
      SignedInfoAndDescendants.Add("DigestMethod"); 
      SignedInfoAndDescendants.Add("DigestValue"); 
      if (!SignedInfoAndDescendants.Contains(localName)) 
      { 
       prefix = GetPrefix(namespaceURI); 
      } 
     } 

     return base.CreateElement(prefix, localName, namespaceURI); 
    } 

    /// <summary> 
    /// Select the standar prefix for the namespaceURI provided 
    /// </summary> 
    /// <param name="namespaceURI"></param> 
    /// <returns></returns> 
    public static string GetPrefix(string namespaceURI) 
    { 
     if (namespaceURI == "http://www.w3.org/2001/10/xml-exc-c14n#") 
      return "ec"; 
     else if (namespaceURI == SignedXml.XmlDsigNamespaceUrl) 
      return "ds"; 

     return string.Empty; 
    } 
} 
} 

này được sử dụng trên SignedXml Creation:

// Create a new XML document. 
    XmlDsigDocument doc = new XmlDsigDocument(); 

    // Load the passed XML file using its name. 
    doc.Load(new XmlTextReader(FileName)); 

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

Bạn có thể thấy file nguồn đầy đủ tại:

https://social.msdn.microsoft.com/Forums/en-US/cd595379-f66a-49c8-8ca2-62acdc58b252/add-prefixds-signedxml?forum=xmlandnetfx

0

Tôi đồng ý rằng Tiền tố không nên quan trọng, nhưng ...

XML trở thành nhiều dễ dàng hơn trong C# nếu bạn sử dụng XPath:

var s = signedXml.GetXml(); 
XmlNodeList nodes = s.SelectNodes("descendant-or-self::*"); 
foreach (XmlNode childNode in nodes) 
{ 
    childNode.Prefix = "dsig"; 
} 
0

Mã George Dima cung cấp công trình.

Tôi sẽ giải thích cách hoạt động.

Khi bạn gọi phương thức ComputeSignature, phương thức này sẽ tạo ra Giá trị Chữ ký bằng cách phân tích giá trị của nút SignedInfo.

Mã do George Dima cung cấp thêm tiền tố vào nút SignedInfo và con của nó TRƯỚC KHI nhận giá trị thông báo. Điều này sẽ không thêm tiền tố để cấu trúc xml toàn

này là phương pháp mà tạo ra các giá trị tiêu hóa của nút signedinfo

private byte[] GetC14NDigest(HashAlgorithm hash, string prefix) 
{   
    XmlDocument document = new XmlDocument(); 
    document.PreserveWhitespace = true; 
    XmlElement e = this.SignedInfo.GetXml(); 
    document.AppendChild(document.ImportNode(e, true));   
    Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject; 

    SetPrefix(prefix, document.DocumentElement); //HERE'S WHERE THE PREFIX IS ADDED TO GET THE DIGEST VALUE 
    canonicalizationMethodObject.LoadInput(document); 
    return canonicalizationMethodObject.GetDigestedOutput(hash); 
} 

Vì vậy, bây giờ bạn có giá trị tiêu hóa của nút SignedInfo VỚI tiền tố , và giá trị này sẽ được sử dụng để có được những giá trị gia tăng Chữ ký, nhưng bạn vẫn kHÔNG có xml với tiền tố, vì vậy nếu bạn chỉ làm điều này

signedXml.GetXml(); 

bạn sẽ nhận được xml mà không có tiền tố và của tất nhiên vì giá trị chữ ký đã được tính toán xem xét trước sửa chữa bạn sẽ có một chữ ký không hợp lệ vì vậy những gì bạn phải làm là gọi GetXml vượt qua nó giá trị của tiền tố, trong trường hợp này "ds" như thế này

signedXml.GetXml("ds");