对于Web应用程序,我想创建一个简单但有效的许可系统。在C#中,这有点困难,因为任何安装了Reflector的人都可以查看我的解密方法。
有哪些方法可以加密C#中相当防篡改的文件?
答案 0 :(得分:38)
听起来您希望使用公共/私有加密技术来签署许可证令牌(例如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框架也会因安全异常而死亡,因为强名称将不再与程序集本身匹配。
要从客户端程序集中提取要使用类似于以下代码的公钥:
/// <summary>
/// Retrieves an RSA public key from a signed assembly
/// </summary>
/// <param name="assembly">Signed assembly to retrieve the key from</param>
/// <returns>RSA Crypto Service Provider initialised with the key from the assembly</returns>
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文件进行签名,然后从程序集上的公钥进行验证。
<强>更新强>
添加了up to date blog post,其中详细介绍了许可文件
答案 1 :(得分:7)
使用签名的XML文件。使用密钥对的私钥部分对其进行签名,并使用软件中的公钥部分进行检查。这使您有机会检查许可证是否已被更改,并检查许可证文件是否有效。
MSDN中记录了签名和检查签名的XML文件。
您在自己的公司签署许可文件并将许可文件发送给客户然后将许可文件放在一个文件夹供您阅读,这当然是合乎逻辑的。
当然,人们可以删除/破解你的分布式程序集并删除xml签名检查,但是不管你做什么,他们总是能够这样做。
答案 2 :(得分:6)
Wolfwyrd的答案非常好,但我只想提供一个更简单的Wolfwyrd GetPublicKeyFromAssembly
方法版本(它使用了Wolfwyrd图书馆提供的大量辅助方法)。
在此版本中,这是您需要的所有代码:
/// <summary>
/// Extracts an RSA public key from a signed assembly
/// </summary>
/// <param name="assembly">Signed assembly to extract the key from</param>
/// <returns>RSA Crypto Service Provider initialised with the public key from the assembly</returns>
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;
}
答案 3 :(得分:1)
为什么需要对其进行加密?如果它是篡改你害怕(例如有人增加用户数量),你可能只是用例如签名来签名吗?你的组织的数字证书呢?
答案 4 :(得分:1)
通过许可提供某种安全性的唯一方法是强制在线登录自己持有的凭证(真的是抽象的说法)。
所有其他方法需要花费更多时间,因此需要更多资金来破解和滥用您的软件,而不是购买许可证。
.NET有一些很好的加密类,但正如您所提到的,如果您编写许可证的编码,每个人都可以轻松地对其进行反编译。
答案 5 :(得分:1)
MSDN示例似乎使用默认参数,这会导致特定于计算机的签名,从而无法在一台计算机上签名并在任意其他计算机上进行验证。我修改了这些示例中的逻辑,以便在签名机器上使用我的snk中的键,并在验证机器中使用我的程序集中的键。这是使用上面链接的(非常好的)ExcryptionUtils.cs示例中的MSDN示例和例程中的逻辑完成的。
为了签名文件,我使用了这个:
RSACryptoServiceProvider rsaKey = EncryptionUtils.GetRSAFromSnkFile(keyFilePath);
为了验证文件,我使用了这个:
RSACryptoServiceProvider rsaKey = EncryptionUtils.GetPublicKeyFromAssembly
(System.Reflection.Assembly.GetExecutingAssembly());
BTW:我发现XML签名验证忽略了XML注释。
答案 6 :(得分:0)
或者您可能希望将许可证绑定到特定计算机,例如通过基于PC的c驱动器的md5值生成许可证密钥。那么你的许可证将是机器特定的。
答案 7 :(得分:0)
实施签名/验证码时,请注意不要将其放在单独的程序集中。代码访问安全防篡改现在很容易绕过,如文章CAS Tamper-Proofing is Broken: Consequences for Software Licensing中所述。
强制性免责声明&amp;插件:我共同创办的公司生产OffByZero Cobalt licensing solution。
答案 8 :(得分:-1)
RE:不要在代码中包含整个密钥。使用sn -p将公共部分提取到文件。在您分发的代码中使用它来验证许可证。
使用MSDN文章中的代码,我创建了一个小应用程序(LicMaker)来实现此目的。该应用程序使用完整密钥对进行签名。输入是未签名的.XML许可证文件。输出是签名.LIC文件中的原始XML +签名。我的产品也使用相同的完整密钥对文件进行签名。该产品验证.LIC文件未被篡改。效果很好。我没有使用sn -p来解决这个问题。