WCF,C#:发送签名的LicenseKey(RSA)

时间:2016-04-27 12:42:35

标签: c# wcf rsa signing

我阅读了多个教程等,但我仍然不确定正确的方法是什么。

这里的情景:

我们的客户(客户端始终是服务器)在我们的网络中安装我们的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吗?

感谢您的帮助

1 个答案:

答案 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);
        }
    }
}