WCF、C#:发送签名的 LicenseKey (RSA)
WCF, C#: Send a signed LicenseKey (RSA)
我看了很多教程等等,但我仍然不确定正确的方法是什么。
场景如下:
我们的客户(客户端始终是服务器)在他们的网络中安装我们的网络应用程序。每个客户端都需要一个包含多个模块的许可证密钥。
为确保他们不会篡改许可证密钥(其中包含他们购买的模块等),我想使用非对称密钥对其进行签名。
客户端(客户端始终是服务器)想要在我们的服务器上激活许可证。
服务器知道客户端购买了哪种license/modules。
所以它会创建一个响应,其中应该包含签名的许可证密钥。
响应看起来像这样(客户就是服务 returns)
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
}
我想做的是签署"LicenseKey"。
客户端收到此许可证密钥并将其存储在数据库中,每 X 分钟验证一次它的完整性。
这是我的 question/problem。
我应该如何签署 LicenseKey,以便仅签署 WCF 响应的 "LicenseKey" 部分,重要的是,可以存储并且 used/verified 在 WCF 请求之外?
我知道 WCF 提供 "ProtectionLevel.Sign",但我必须创建 X509 证书才能使其正常工作,对吗?
这甚至会 work/verify 在 WCF 之外吗?
或者我应该编写一个消息拦截器来手动签署我的 LicenseKey 吗?
感谢您的帮助
由于使用签名保护许可证密钥的完整性是一项业务要求,我认为它应该是密钥数据结构本身的一部分。同样,签名应该在创建密钥时创建,而不是稍后在 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);
}
}
}
我看了很多教程等等,但我仍然不确定正确的方法是什么。
场景如下:
我们的客户(客户端始终是服务器)在他们的网络中安装我们的网络应用程序。每个客户端都需要一个包含多个模块的许可证密钥。 为确保他们不会篡改许可证密钥(其中包含他们购买的模块等),我想使用非对称密钥对其进行签名。
客户端(客户端始终是服务器)想要在我们的服务器上激活许可证。 服务器知道客户端购买了哪种license/modules。 所以它会创建一个响应,其中应该包含签名的许可证密钥。
响应看起来像这样(客户就是服务 returns)
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
}
我想做的是签署"LicenseKey"。 客户端收到此许可证密钥并将其存储在数据库中,每 X 分钟验证一次它的完整性。
这是我的 question/problem。
我应该如何签署 LicenseKey,以便仅签署 WCF 响应的 "LicenseKey" 部分,重要的是,可以存储并且 used/verified 在 WCF 请求之外?
我知道 WCF 提供 "ProtectionLevel.Sign",但我必须创建 X509 证书才能使其正常工作,对吗? 这甚至会 work/verify 在 WCF 之外吗?
或者我应该编写一个消息拦截器来手动签署我的 LicenseKey 吗?
感谢您的帮助
由于使用签名保护许可证密钥的完整性是一项业务要求,我认为它应该是密钥数据结构本身的一部分。同样,签名应该在创建密钥时创建,而不是稍后在 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);
}
}
}