我阅读了多个教程等,但我仍然不确定正确的方法是什么。
这里的情景:
我们的客户(客户端始终是服务器)在我们的网络中安装我们的Web应用程序。每个客户端都需要一个包含多个模块的许可证密钥。 为了确保他们不会篡改许可证密钥(包含他们购买的模块等),我想用非对称密钥签名。
客户端(客户端始终是服务器)想要在我们的服务器上激活许可证。 服务器知道客户购买了哪种许可证/模块。 所以它创建一个应该包含签名许可证密钥的响应。
响应看起来像这样(客户是服务返回的内容)
public class Customer
{
public string Identifier {get; set;}
public LicenseKey LicenseKey {get; set; }
}
public class LicenseKey
{
public List<License>{get; set;}
}
public class License
{
//actual LicensingData
}
我想要做的是签署&#34; LicenseKey&#34;。 客户端接收此许可证密钥并将其存储在数据库中,并且每隔X分钟就会验证其完整性。
所以,这是我的问题/问题。
我应该如何签署LicenseKey,只有&#34; LicenseKey&#34; WCF响应的一部分是签名的,重要的是,可以在WCF请求之外存储和使用/验证吗?
我知道WCF提供&#34; ProtectionLevel.Sign&#34;,但是我必须创建X509证书才能让它工作,对吧? 这甚至可以在WCF之外工作/验证吗?
或者我应该编写一个消息拦截器来手动签署我的LicenseKey吗?
感谢您的帮助
答案 0 :(得分:0)
由于使用签名保护许可证密钥的完整性是一项业务要求,我认为它应该是关键数据结构本身的一部分。类似地,签名应该在创建密钥时创建,而不是稍后在WCF堆栈中应用(这在技术上可能当然是错误的地方恕我直言)。
如何签署仲裁数据?
这是使用RSACryptoServiceProvider
的快速演示。当然,如果需要,也可以使用完整的X.509证书。
using System.Security.Cryptography;
using System.Text;
namespace SignatureDemo
{
public class Demo
{
static void Main(string[] args)
{
// "Main" is from the client point of view
LicenseServer server = new LicenseServer();
Signer signer = new Signer();
// Obtain a key from the server
LicenseKey key = server.GetKey("nodots");
// Verify the signature of the unchanged key, this will result to true
bool isValid1 = signer.VerifySignature(key, server.PublicKey);
// Manipulate the license
key.License.FeatureB = true;
// Verify the signature of the changed key, this will result to false
bool isValid2 = signer.VerifySignature(key, server.PublicKey);
}
}
public class LicenseServer
{
// Contains both public and private key. This must stay secret!
private readonly string _keyPair;
private readonly Signer _signer = new Signer();
public LicenseServer()
{
// Create demo key pair
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
_keyPair = rsa.ToXmlString(true);
PublicKey = rsa.ToXmlString(false);
}
}
public string PublicKey
{
get;
}
public LicenseKey GetKey(string customerName)
{
LicenseKey key = new LicenseKey(new License(customerName, true, false));
key.Signature = _signer.CreateSignature(key, _keyPair);
return key;
}
}
public class LicenseKey
{
public LicenseKey(License license)
{
License = license;
}
public License License
{
get;
set;
}
public byte[] Signature
{
get;
set;
}
}
public class License
{
public License(string customerName, bool featureA, bool featureB)
{
CustomerName = customerName;
FeatureA = featureA;
FeatureB = featureB;
}
public string CustomerName
{
get;
set;
}
public bool FeatureA
{
get;
set;
}
public bool FeatureB
{
get;
set;
}
}
public class Signer
{
public byte[] CreateSignature(LicenseKey key, string privateKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(privateKey);
return rsa.SignData(ComputeHash(key), CryptoConfig.MapNameToOID("SHA256"));
}
}
public bool VerifySignature(LicenseKey key, string publicKey)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(publicKey);
return rsa.VerifyData(ComputeHash(key), CryptoConfig.MapNameToOID("SHA256"), key.Signature);
}
}
private static byte[] ComputeHash(LicenseKey key)
{
// Create a hash from the given key.
// For demo purposes I'm using a very simple string concatenation of the relevant properties.
string simplifiedHash = string.Concat(key.License.CustomerName, key.License.FeatureA, key.License.FeatureB);
return Encoding.UTF8.GetBytes(simplifiedHash);
}
}
}