加密许可证文件的有效方法?

对于Web应用程序,我想创建一个简单但有效的许可系统。 在C#中,这有点困难,因为任何安装了Reflector的人都可以查看我的解密方法。

有哪些方法可以加密C#中相当防篡改的文件?

听起来您希望使用公共/私有加密技术来签署许可证令牌(例如XML片段或文件),以便您可以检测到篡改。 处理它的最简单方法是执行以下步骤:

1)为贵公司生成密钥对。 您可以使用SN工具在Visual Studio命令行中执行此操作。 语法是:

sn -kc:\keypair.snk 

2)使用密钥对强烈命名(即签署)您的客户端应用程序。 您可以使用应用程序属性页面中的签名选项卡进行设置

3)为您的客户创建许可证,这应该是一个XML文档,并使用您的私钥对其进行签名。 这涉及简单地计算数字签名,并且可以在以下位置找到完成它的步骤:

http://msdn.microsoft.com/en-us/library/ms229745.aspx

4)在客户端上,在检查许可证时,您加载XmlDocument并使用您的公钥validation签名以certificate许可证未被篡改。 有关如何执行此操作的详细信息,请访问:

http://msdn.microsoft.com/en-us/library/ms229950.aspx

要绕过密钥分发(即确保客户端使用正确的公钥),您实际上可以从签名的程序集本身中提取公钥。 因此,确保您没有其他密钥来分发,即使有人篡改程序集,.net框架也会因安全exception而死亡,因为强名称将不再与程序集本身匹配。

要从客户端程序集中提取公钥,您需要使用类似于以下内容的代码:

  ///  /// Retrieves an RSA public key from a signed assembly ///  /// Signed assembly to retrieve the key from /// RSA Crypto Service Provider initialised with the key from the assembly public static RSACryptoServiceProvider GetPublicKeyFromAssembly(Assembly assembly) { if (assembly == null) throw new ArgumentNullException("assembly", "Assembly may not be null"); byte[] pubkey = assembly.GetName().GetPublicKey(); if (pubkey.Length == 0) throw new ArgumentException("No public key in assembly."); RSAParameters rsaParams = EncryptionUtils.GetRSAParameters(pubkey); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(rsaParams); return rsa; } 

我已经在Snipt上传了一个包含许多有用的加密工具的示例类: http ://snipt.net/Wolfwyrd/encryption-utilities/,以帮助您顺利上路。

我还在https://snipt.net/Wolfwyrd/sign-and-verify-example/中包含了一个示例程序。 该示例要求您使用encryption utils库将其添加到解决方案中,并提供测试XML文件和SNK文件以进行签名。 项目应设置为使用您生成的SNK进行签名。 它演示了如何使用SNK中的私钥对测试XML文件进行签名,然后从程序集上的公钥进行validation。

更新

添加了一个最新的博客文章 ,其中详细介绍了许可证文件

使用签名的XML文件。 使用密钥对的私钥部分对其进行签名,并使用软件中的公钥部分进行检查。 这使您有机会检查许可证是否已被更改,以及检查许可证文件是否有效。

MSDN中记录了对签名的XML文件的签名和检查。

您在自己的公司签署许可文件并将许可文件发送给客户然后将许可文件放在一个文件夹供您阅读,这当然是合乎逻辑的。

当然,人们可以删除/破解你的分布式程序集并删除xml签名检查,但是再次,无论你做什么,他们总是能够这样做。

Wolfwyrd的答案非常好,但我只是想提供一个更简单的Wolfwyrd的GetPublicKeyFromAssembly方法版本(它使用了Wolfwyrd图书馆提供的大量帮助方法)。

在这个版本中,这是您需要的所有代码:

 ///  /// Extracts an RSA public key from a signed assembly ///  /// Signed assembly to extract the key from /// RSA Crypto Service Provider initialised with the public key from the assembly private RSACryptoServiceProvider GetPublicKeyFromAssembly(Assembly assembly) { // Extract public key - note that public key stored in assembly has an extra 3 headers // (12 bytes) at the front that are not part of a CAPI public key blob, so they must be removed byte[] rawPublicKeyData = assembly.GetName().GetPublicKey(); int extraHeadersLen = 12; int bytesToRead = rawPublicKeyData.Length - extraHeadersLen; byte[] publicKeyData = new byte[bytesToRead]; Buffer.BlockCopy(rawPublicKeyData, extraHeadersLen, publicKeyData, 0, bytesToRead); RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider(); publicKey.ImportCspBlob(publicKeyData); return publicKey; } 

你为什么需要加密它? 如果它是篡改你害怕(例如有人增加用户数量),你可能只是用例如你组织的数字证书签名吗?

为许可提供某种安全性的唯一方法是强制在线登录自己持有的凭证(真正抽象的说法)。

所有其他方法需要更多时间,因此需要更多资金来实施,以破解和滥用您的软件而不是购买许可证。

.NET有一些很好的加密类,但正如您所提到的,如果您编写许可证的编码,每个人都可以轻松地对其进行反编译。

MSDN示例似乎使用默认参数,这会导致特定于计算机的签名,这样您就无法在一台计算机上签名并在任意其他计算机上进行validation。 我修改了这些示例中的逻辑,以便在签名机器上使用我的snk中的键和在validation机器中使用我的程序集中的键。 这是使用MSDN示例中的逻辑和上面链接的(非常好的)ExcryptionUtils.cs示例中的例程完成的。

为了签名文件,我使用了这个:

 RSACryptoServiceProvider rsaKey = EncryptionUtils.GetRSAFromSnkFile(keyFilePath); 

为了validation文件,我使用了这个:

 RSACryptoServiceProvider rsaKey = EncryptionUtils.GetPublicKeyFromAssembly (System.Reflection.Assembly.GetExecutingAssembly()); 

BTW:我发现XML签名validation忽略了XML注释。

或者您可能希望将许可证绑定到特定计算机,例如通过根据计算机的c驱动器的md5值生成许可证密钥。 那么你的许可证将是机器特定的。

实施签名/validation代码时,请注意不要将其放在单独的程序集中。 代码访问安全防篡改现在很容易绕过,如CAS防篡改文章中所述:软件许可的后果 。

强制免责声明和插件:我共同创办的公司生产OffByZero Cobalt许可解决方案 。

RE:不要在代码中包含整个密钥。 使用sn -p将公共部分提取到文件。 在您分发的代码中使用它来validation许可证。

使用MSDN文章中的代码,我创建了一个小应用程序(LicMaker)来促进这一点。 该应用程序使用完整密钥对进行签名。 输入是未签名的.XML许可证文件。 输出是签名.LIC文件中的原始XML +签名。 我的产品也使用相同的完整密钥对文件进行签名。 产品validation.LIC文件未被篡改。 效果很好。 我没有使用sn -p来解决这个问题。