我正在尝试为我的软件构建更新程序。到目前为止,这不是一个艰巨的任务,但我想签署文件,以防止受到黑客攻击和修改(因为它将允许安装有害的软件)。
我在MSDN和各种博客中找到了一些教程,它们完美地展示了如何签署XML文件。得到了这个 - 我有一个签名附加到我的文件。
以某种方式未涵盖的事情是:验证如何在不同的计算机上运行?我不知道如何提供必要的数据来验证它。据我所知,我需要私钥才能验证签名(包含公钥)。现在我该怎么提供那个呢?如果我只是将它存储在应用程序中,即使加密也可以轻松抓取它。
我尝试过的另一种可能的方法是嵌入X509证书。我甚至得到了一些代码来生成这样的代码,但随后它将始终显示证书来自未知来源。
有没有提示用户安装证书的方法?或者更好的是没有安装东西?
到目前为止,我还没有找到任何关于此事的内容。
答案 0 :(得分:3)
忘记这是XML。
数字签名依赖于加密的简单原则,更具体地说是依赖密码术,其中有2个密钥(公共密钥和私有密钥)。
您使用私钥进行签名并将签名文档提供给某人。有人用您的公钥验证签名。公钥 - 正如其名称所示 - 是公开的,可以分发。私钥仅用于签名。公众仅用于验证签名。
对于XML,您可以使用digital signature个人资料。您可以签署一个XML文档,该文档将生成一些可以附加到XML的二进制内容。您还可以附加公钥。由于公钥将成为已签名内容的一部分,因此您知道它也未被篡改。此外,您可以将公钥视为PKI的一部分。这可能是您首先选择信任公钥的方式。
签名内容提供:
关于验证,在Wikipedia和许多其他网站上解释了高级原则。您必须告诉您的应用程序在何处找到用于验证XML的密钥。
有关更多示例,请查看standardization body。
最后,MSDN上有很多关于该主题的文章和示例代码。快速谷歌提出了这篇文章:How to: Verify the Digital Signatures of XML Documents
道路的另一个链接......这是primer on crypto,写得非常好。它讨论了密钥及其用法。
答案 1 :(得分:1)
感谢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);
}