2

我目前正在尝试为我的软件构建更新程序。到目前为止,这不是一项艰巨的任务,但我想对文件进行签名,以防止在这些文件被黑客入侵和修改时造成伤害(因为它会允许安装有害软件)。

我在 MSDN 和各种博客中找到了一些教程,它们完美地展示了如何签署 XML 文件。得到这个工作 - 我有一个签名附加到我的文件。

不知何故没有涉及的是:验证如何在不同的计算机上工作?我不明白我应该如何提供必要的数据来验证它。据我了解,我需要私钥来验证签名(其中包含公钥)。现在我将如何提供那个?如果我只是将它存储在应用程序中,即使加密也可以轻松抓取。

我尝试过的另一种可能的方法是嵌入 X509 证书。我什至得到了一些代码来生成这样的代码,但它总是会显示证书来自未知来源。

有什么办法不提示用户安装证书?还是完全不安装东西更好?

到目前为止,我还没有发现任何关于这件事的信息。

4

2 回答 2

4

忘记这是 XML 的事实。

数字签名依赖于简单的密码学原理,更具体地说是非对称密码学,其中您有 2 个密钥(一个公共密钥和一个私有密钥)。

您使用您的私钥签名并将签名的文档提供给某人。有人使用您的公钥验证签名。公钥——顾名思义——是公开的并且可以分发。私钥仅用于签名。公众仅用于验证签名。

对于 XML,您可以使用数字签名配置文件。您可以签署一个 XML 文档,这将产生一些您可以附加到 XML 的二进制内容。您还可以附加公钥。由于公钥将成为签名内容的一部分,因此您知道它也没有被篡改。此外,您可以将公钥视为 PKI 的一部分。这可能是您首先选择信任公钥的方式。

签名内容提供:

  • 正直
  • 不可否认性

关于验证,高级原则在Wikipedia和许多其他网站上进行了解释。您必须告诉您的应用程序在哪里找到用于验证 XML 的密钥。

查看标准化机构以获取更多示例。

最后,MSDN 上有很多关于该主题的文章和示例代码。一个快速的谷歌想出了这篇文章:如何:验证 XML 文档的数字签名

道路的另一个链接......这是关于加密的入门读物,写得很好。它讨论了密钥及其用法。

于 2016-02-25T01:36:30.060 回答
2

感谢 David Brossard 的回答,我找到了解决方案。好吧,对于那些可能会徘徊的人来说,这是我的代码(签名代码必须稍作修改,因为它包含我的签名工具中的内容):

签约

    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;
    }

确认

    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);
    }
于 2016-02-25T02:42:15.720 回答