【问题标题】:WCF, C#: Send a signed LicenseKey (RSA)WCF、C#:发送签名的 LicenseKey (RSA)
【发布时间】:2016-04-27 12:42:35
【问题描述】:

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

这里的场景:

我们的客户端(客户端始终是服务器)在他们的网络中安装我们的 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 请求之外存储和使用/验证?

我知道 WCF 提供“ProtectionLevel.Sign”,但我必须创建 X509 证书才能使其工作,对吗? 这甚至可以在 WCF 之外工作/验证吗?

或者我应该编写一个消息拦截器来手动签署我的 LicenseKey?

感谢您的帮助

【问题讨论】:

  • 不确定我是否理解正确,但听起来这是一个实际的业务需求(因为您想稍后存储/验证签名实体)。所以恕我直言,签名应该首先进入 LicenseKey 或 License。 (编辑澄清:与通过保护级别进行 WCF 消息签名相反,WCF 消息签名旨在确保客户端和服务器之间传输数据的完整性。此外,从技术上讲,可以在消息检查器中签署任何您想要的内容,但我会争辩这是错误的地方。)
  • 是的,这是业务需求。所以,这意味着:我假设拦截消息的发送并签署 LicenseKey 部分。
  • 您的评论和我的编辑重叠。当它是业务需求时,LicenseKey 或 License 不应该包含签名数据吗?
  • 我在签名和加密方面没有太多经验。但是,是的,LicenseKey 应该包含签名数据。但是,如果不在 Message Inspector 中,我应该如何签署 LicenseKey?我不需要用 LicenseKey 对 XML 部分进行签名吗?据我所知,我无法签署 C# 对象。

标签: c# wcf rsa signing


【解决方案1】:

由于使用签名保护许可证密钥的完整性是一项业务需求,我认为它应该是密钥数据结构本身的一部分。同样,应该在创建密钥时创建签名,而不是稍后在 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);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 2012-01-16
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多