I'm currently trying to build an updater for my software. So far this is not a hard task but I'd like to sign files in order to prevent harm in case these get hacked and modified (as it would allow installing harmful software).
我目前正在为我的软件构建一个更新程序。到目前为止,这并不是一项艰巨的任务,但我希望签署文件,以防这些文件被黑客攻击和修改(因为它允许安装有害的软件)。
I found some tutorials on MSDN and in various blogs which perfectly show how to sign an XML file. Got this working - I have a signature appended to my file.
我在MSDN和各种博客上找到了一些教程,它们完美地展示了如何签署XML文件。我有一个签名附在我的文件上。
The thing that somehow isn't covered is: How does validation work on different computers? I don't get how I should provide the necessary data to validate it. As far as I understood I need the private key in order to validate the signature (which contains the public key). Now how would I provide that one? If I simply store it in the application, it can be grabbed easily, even if encrypted.
不知何故,没有涉及的是:验证如何在不同的计算机上工作?我不知道如何提供必要的数据来验证它。就我所知,我需要私钥来验证签名(它包含公钥)。现在我该怎么做呢?如果我只是将它存储在应用程序中,就可以很容易地获取它,即使是加密的。
Another possible approach I've tried was to embed a X509 certificate. I even got some code to generate such one, but then it'll always show that the certificate comes from an unknown source.
我尝试过的另一种方法是嵌入一个X509证书。我甚至有一些代码来生成这样的代码,但是它总是显示证书来自一个未知的源。
Is there any way without prompting the user for installing certificates? Or better without installing stuff at all?
有没有办法不提示用户安装证书?或者干脆不安装东西?
So far I haven't found anything on that matter.
到目前为止,我还没有发现任何有关这方面的消息。
2 个解决方案
#1
3
Forget the fact this is XML.
忘了这是XML吧。
Digital signatures rely on the simple principle of cryptography and more specifically assymmetric cryptography where you have 2 keys (a public one and a private one).
数字签名依赖于简单的密码学原理,更具体地说,依赖于有两个密钥(一个公钥和一个私钥)的对称密码学。
You sign with your private key and give the signed document to someone. That someone validates the signature with your public key. The public key - as its name indicates - is public and can be distributed. The private key is only used for signing. The public is only used for validating the signature.
您使用您的私钥签名并将签名的文档交给某人。有人用您的公钥验证签名。公钥(顾名思义)是公开的,可以分发。私钥仅用于签名。公众只用于验证签名。
With respect to XML, you can use the digital signature profile. You can sign an XML document which will result in some binary content which you can attach to the XML. You can also attach the public key. Since the public key will be part of the signed content, you know it hasn't been tampered with either. Also, you could consider the public key to be part of a PKI. This could be how you choose to trust the public key in the first place.
关于XML,您可以使用数字签名配置文件。您可以签署一个XML文档,它将产生一些二进制内容,您可以将这些内容附加到XML中。您还可以附加公钥。因为公钥将是签名内容的一部分,所以您知道它也没有被篡改。此外,您可以将公钥视为PKI的一部分。这可能是您首先选择信任公钥的方式。
Signing content provides:
签署内容提供了:
- integrity
- 完整性
- non-repudiation
- 不可抵赖性
With respect to validation, the high-level principle is explained on Wikipedia and many other sites. You will have to tell your app where to locate the key with which to validate the XML.
关于验证,在*和其他网站上解释了高级原则。您必须告诉应用程序在哪里找到验证XML的键。
Have a look at the standardization body for more examples.
有关更多示例,请参阅标准化组织。
Lastly, the MSDN has lots of articles and sample code on the topic. A quick google came up with this article: How to: Verify the Digital Signatures of XML Documents
最后,MSDN有很多关于这个主题的文章和示例代码。谷歌提供了这篇文章:如何:验证XML文档的数字签名
One more link for the road... Here is a primer on crypto which is quite well written. It talks about keys and their usage.
还有一条路要走……这是一本关于密码的入门书,写得很好。它讨论了键和它们的用法。
#2
1
Thanks to David Brossard's answer I've found the solution. Well for those who may prowl across that, here's my code (signing code must be modified a little as it contains stuff from my signing tool):
多亏了David Brossard的回答,我找到了解决方案。好吧,对于那些想要了解这些的人,这里是我的代码(签名代码必须稍微修改一下,因为它包含了我的签名工具):
Signing
签署
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;
}
Verification
验证
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);
}
#1
3
Forget the fact this is XML.
忘了这是XML吧。
Digital signatures rely on the simple principle of cryptography and more specifically assymmetric cryptography where you have 2 keys (a public one and a private one).
数字签名依赖于简单的密码学原理,更具体地说,依赖于有两个密钥(一个公钥和一个私钥)的对称密码学。
You sign with your private key and give the signed document to someone. That someone validates the signature with your public key. The public key - as its name indicates - is public and can be distributed. The private key is only used for signing. The public is only used for validating the signature.
您使用您的私钥签名并将签名的文档交给某人。有人用您的公钥验证签名。公钥(顾名思义)是公开的,可以分发。私钥仅用于签名。公众只用于验证签名。
With respect to XML, you can use the digital signature profile. You can sign an XML document which will result in some binary content which you can attach to the XML. You can also attach the public key. Since the public key will be part of the signed content, you know it hasn't been tampered with either. Also, you could consider the public key to be part of a PKI. This could be how you choose to trust the public key in the first place.
关于XML,您可以使用数字签名配置文件。您可以签署一个XML文档,它将产生一些二进制内容,您可以将这些内容附加到XML中。您还可以附加公钥。因为公钥将是签名内容的一部分,所以您知道它也没有被篡改。此外,您可以将公钥视为PKI的一部分。这可能是您首先选择信任公钥的方式。
Signing content provides:
签署内容提供了:
- integrity
- 完整性
- non-repudiation
- 不可抵赖性
With respect to validation, the high-level principle is explained on Wikipedia and many other sites. You will have to tell your app where to locate the key with which to validate the XML.
关于验证,在*和其他网站上解释了高级原则。您必须告诉应用程序在哪里找到验证XML的键。
Have a look at the standardization body for more examples.
有关更多示例,请参阅标准化组织。
Lastly, the MSDN has lots of articles and sample code on the topic. A quick google came up with this article: How to: Verify the Digital Signatures of XML Documents
最后,MSDN有很多关于这个主题的文章和示例代码。谷歌提供了这篇文章:如何:验证XML文档的数字签名
One more link for the road... Here is a primer on crypto which is quite well written. It talks about keys and their usage.
还有一条路要走……这是一本关于密码的入门书,写得很好。它讨论了键和它们的用法。
#2
1
Thanks to David Brossard's answer I've found the solution. Well for those who may prowl across that, here's my code (signing code must be modified a little as it contains stuff from my signing tool):
多亏了David Brossard的回答,我找到了解决方案。好吧,对于那些想要了解这些的人,这里是我的代码(签名代码必须稍微修改一下,因为它包含了我的签名工具):
Signing
签署
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;
}
Verification
验证
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);
}