对于Web应用程序,我想创建一个简单但有效的许可系统.在C#中,这有点困难,因为任何安装了Reflector的人都可以查看我的解密方法.
有哪些方法可以加密C#中相当防篡改的文件?
听起来您希望使用公共/私有加密技术来签署许可证令牌(例如XML片段或文件),以便您可以检测到篡改.处理它的最简单方法是执行以下步骤:
1)为贵公司生成密钥对.您可以使用SN工具在Visual Studio命令行中执行此操作.语法是:
sn -k c:\keypair.snk
2)使用密钥对强烈命名(即签署)您的客户端应用程序.您可以使用应用程序属性页面中的签名选项卡进行设置
3)为您的客户创建一个许可证,这应该是一个XML文档,并使用您的私钥对其进行签名.这涉及简单地计算数字签名,并且可以在以下位置找到完成它的步骤:
http://msdn.microsoft.com/en-us/library/ms229745.aspx
4)在客户端上,在检查许可证时,您加载XmlDocument并使用您的公钥验证签名以证明许可证未被篡改.有关如何执行此操作的详细信息,请访问:
http://msdn.microsoft.com/en-us/library/ms229950.aspx
要绕过密钥分发(即确保客户端使用正确的公钥),您实际上可以从签名的程序集本身中提取公钥.因此,确保您没有其他密钥进行分发,即使有人篡改程序集,.net框架也会因安全异常而死亡,因为强名称将不再与程序集本身匹配.
要从客户端程序集中提取公钥,您需要使用类似于以下内容的代码:
////// 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文件进行签名,然后从程序集上的公钥进行验证.
更新
添加了一个最新的博客文章,其中详细介绍了许可证文件
使用签名的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; }