2016-02-25 3 views
1

J'essaie actuellement de créer un programme de mise à jour pour mon logiciel. Jusqu'à présent, ce n'est pas une tâche difficile, mais je voudrais signer des fichiers afin de prévenir les dommages au cas où ceux-ci seraient piratés et modifiés (car cela permettrait d'installer des logiciels nuisibles).Comment valider des documents XML signés numériquement en C#?

J'ai trouvé quelques tutoriels sur MSDN et dans divers blogs qui montrent parfaitement comment signer un fichier XML. Ça a marché - j'ai une signature ajoutée à mon dossier.

Ce qui n'est pas couvert en quelque sorte est: Comment fonctionne la validation sur différents ordinateurs? Je ne comprends pas comment je devrais fournir les données nécessaires pour le valider. Pour autant que j'ai compris, j'ai besoin de la clé privée pour valider la signature (qui contient la clé publique). Maintenant, comment pourrais-je fournir celui-là? Si je le stocke simplement dans l'application, il peut être saisi facilement, même s'il est crypté.

Une autre approche possible que j'ai essayé était d'incorporer un certificat X509. J'ai même obtenu du code pour en générer un, mais cela montrera toujours que le certificat provient d'une source inconnue.

Y at-il un moyen sans inviter l'utilisateur à installer des certificats? Ou mieux sans installer des trucs du tout?

Jusqu'à présent, je n'ai rien trouvé à ce sujet.

Répondre

3

Oubliez le fait que ce soit XML.

Les signatures numériques reposent sur le principe simple de la cryptographie et plus particulièrement de la cryptographie asymétrique où vous avez 2 clés (une publique et une privée).

Vous vous connectez avec votre clé privée et donnez le document signé à quelqu'un. Que quelqu'un valide la signature avec votre clé publique. La clé publique - comme son nom l'indique - est publique et peut être distribuée. La clé privée est uniquement utilisée pour la signature. Le public est seulement utilisé pour valider la signature.

En ce qui concerne XML, vous pouvez utiliser le profil digital signature. Vous pouvez signer un document XML qui aboutira à du contenu binaire que vous pouvez attacher au code XML. Vous pouvez également attacher la clé publique. Puisque la clé publique fera partie du contenu signé, vous savez qu'elle n'a pas été falsifiée non plus. En outre, vous pouvez considérer la clé publique comme faisant partie d'une infrastructure à clé publique. Cela pourrait être la façon dont vous choisissez de faire confiance à la clé publique en premier lieu.

contenu de signature fournit:

  • intégrité
  • non-répudiation

En ce qui concerne la validation, le principe de haut niveau est expliqué sur Wikipedia et bien d'autres sites. Vous devrez indiquer à votre application où trouver la clé avec laquelle valider le fichier XML. Regardez le standardization body pour plus d'exemples. Enfin, le MSDN a beaucoup d'articles et d'exemples de code sur le sujet. Un rapide google est venu avec cet article: How to: Verify the Digital Signatures of XML Documents

Encore un lien pour la route ... Voici un primer on crypto qui est assez bien écrit. Il parle des clés et de leur utilisation.

+0

Donc, les données qui sont attachées au fichier XML peuvent être validées avec ** juste ** la clé publique? La clé privée est juste utilisée pour signer, n'est-ce pas? – SharpShade

+0

Oui, c'est correct. –

+0

Ah, eh bien, alors j'ai probablement mal compris le principe de cryptage/signature asymétrique. C'est super, alors je pense que je peux facilement modifier le code que j'ai déjà pour le faire fonctionner :) Merci! – SharpShade

1

Grâce à la réponse de David Brossard, j'ai trouvé la solution. Eh bien pour ceux qui rôdent à travers que, voici mon code (signature de code doit être modifié un peu, car il contient des trucs de mon outil de signature):

signature

private static int Sign(Options options) 
    { 
     XmlDocument document = new XmlDocument {PreserveWhitespace = false}; 
     try 
     { 
      document.Load(options.File); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine($"Invalid XML file: {0}.", ex.Message); 
      return -3; 
     } 

     XmlElement signature; 
     try 
     { 
      RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048); 
      if (!string.IsNullOrEmpty(options.Key) && File.Exists(options.Key)) 
      { 
       using (StreamReader reader = new StreamReader(options.Key)) 
        rsa.FromXmlString(reader.ReadToEnd()); 
      } 
      else 
      { 
       FileInfo fi = new FileInfo(options.File); 
       if (fi.DirectoryName == null) return -7; 
       string keyFile = Path.Combine(fi.DirectoryName, "signature.key"); 
       using (StreamWriter writer = new StreamWriter(keyFile)) 
        writer.Write(rsa.ToXmlString(true)); 
      } 


      SignedXml signedXml = new SignedXml(document) {SigningKey = rsa}; 
      KeyInfo info = new KeyInfo(); 
      info.AddClause(new RSAKeyValue(rsa)); 
      signedXml.KeyInfo = info; 

      Reference reference = new Reference {Uri = ""}; 

      reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); 
      reference.AddTransform(new XmlDsigC14NTransform()); 

      signedXml.AddReference(reference); 
      signedXml.ComputeSignature(); 

      signature = signedXml.GetXml(); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine($"Error signing XML file: {0}.", ex.Message); 
      return -4; 
     } 

     try 
     { 
      if (document.DocumentElement == null) 
      { 
       Console.WriteLine("Document has no document element."); 
       return -6; 
      } 
      document.DocumentElement.AppendChild(document.ImportNode(signature, true)); 
      document.Save(options.File); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine($"Error saving signed XML file: {0}.", ex.Message); 
      return -5; 
     } 

     return 0; 
    } 

Vérification

public static bool Verify(XmlDocument document) 
    { 
     if (document == null) throw new ArgumentNullException(nameof(document), "XML document is null."); 

     SignedXml signed = new SignedXml(document); 
     XmlNodeList list = document.GetElementsByTagName("Signature"); 
     if (list == null) 
      throw new CryptographicException($"The XML document has no signature."); 
     if (list.Count > 1) 
      throw new CryptographicException($"The XML document has more than one signature."); 

     signed.LoadXml((XmlElement)list[0]); 

     RSA rsa = null; 
     foreach (KeyInfoClause clause in signed.KeyInfo) 
     { 
      RSAKeyValue value = clause as RSAKeyValue; 
      if (value == null) continue; 
      RSAKeyValue key = value; 
      rsa = key.Key; 
     } 

     return rsa != null && signed.CheckSignature(rsa); 
    } 
+0

Voulez-vous jeter un oeil à la question similaire s'il vous plaît stackoverflow.com/questions/42440634/xml-signature-element-is-not-declared –