[英]WCF, C#: Send a signed LicenseKey (RSA)
我閱讀了多個教程等,但我仍然不確定正確的方法是什么。
這里的場景:
我們的客戶(客戶端始終是服務器)在我們的網絡中安裝我們的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
}
我想要做的是簽署“LicenseKey”。 客戶端收到此許可證密鑰並將其存儲在數據庫中,並且每隔X分鍾就會驗證其完整性。
所以這是我的問題/問題。
我應該如何簽署LicenseKey,以便只簽署WCF響應的“LicenseKey”部分,並且重要的是,可以在WCF-Request之外存儲和使用/驗證?
我知道WCF提供了“ProtectionLevel.Sign”,但是我必須創建X509證書才能讓它工作,對嗎? 這甚至可以在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);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.