如何生成和验证软件许可密钥?

我目前正在开发一个产品(用c#开发的),可以免费下载和安装,但版本非常有限。要获得所有功能,用户必须支付许可费并获得密钥。然后,该密钥将被输入应用程序以“解锁”完整版本。

像这样使用许可密钥是很常见的,我想知道:

  1. 这个问题通常是怎么解决的?
  2. 如何生成密钥以及应用程序如何验证密钥?
  3. 我怎样才能避免一个密钥被发布在互联网上,并被其他没有支付许可证的人使用(一个基本上不是“他们的”密钥)。

我想我还应该以某种方式将密钥绑定到应用程序的版本,这样就有可能在功能版本中对新密钥收费。

在这种情况下,还有什么需要考虑的吗?

377424 次浏览

我在过去使用过Crypkey。这是许多可用的之一。

使用任何许可方案,您只能在一定程度上保护软件。

简单的答案-无论你使用什么方案都可以被破解。

不要用一个旨在防止黑客的系统来惩罚诚实的客户,因为黑客无论如何都会破解它。

一个简单的散列代码绑定到他们的电子邮件或类似的可能就足够了。当人们需要重新安装或更新硬件时,基于硬件的id总是会成为一个问题。

关于这个问题的好线程: http://discuss.joelonsoftware.com/default.asp?biz.5.82298.34 < / p >

要做到你所要求的一切,唯一的方法就是要求互联网接入和服务器验证。应用程序需要使用密钥登录到服务器,然后需要存储会话详细信息,如IP地址。这将防止密钥在多台不同的机器上使用。这通常不太受应用程序用户的欢迎,除非这是一个非常昂贵和复杂的应用程序,否则不值得这样做。

您可以只拥有应用程序的许可密钥,然后检查客户端密钥是否有效,但是很容易将此密钥分发给其他用户,并且可以使用反编译器生成新密钥。

警告:你不能阻止用户盗版,只能让诚实的用户更容易做正确的事情。

假设你不想为每个用户做一个特殊的构建,那么:

  • 为产品生成一个密钥
  • 取用户名
  • 使用(例如)SHA1连接用户名、密钥和散列
  • 将SHA1散列解压缩为字母数字字符串。这是个人用户的“产品密钥”
  • 在程序中,执行相同的散列,并与产品密钥进行比较。如果相等,好的。

但是,我重复一遍:这并不能阻止盗版


我最近读到,这种方法在密码学上不是很可靠。但是这个解决方案已经很弱了(因为软件本身必须在某个地方包含密钥),所以我不认为这个发现会使解决方案失效。

只是觉得我真的应该提一下;如果您打算从这里推导出其他东西,请小心。

在生成密钥时,不要忘记将版本和构建号连接到计算散列的字符串上。这样就不会有一把钥匙能打开你释放的所有东西。

当你在astalavista.box.sk中找到一些密钥或补丁后,你就会知道你成功地让一些东西流行到有人费心破解。喜乐!

我不知道你想说得多详细

但我相信。net可以访问硬盘序列号。

你可以让程序把它和其他东西(比如网卡的用户名和MAC地址)发送给你

你在此基础上计算出一个代码,然后把密钥发邮件给他们。

他们会阻止他们在拿到钥匙后换机器。

除了已经说过的....

由于中间语言的问题,. net应用程序的任何使用本质上都是容易被破坏的。对. net代码进行简单的反汇编就可以向任何人打开您的产品。他们可以很容易地绕过你的授权代码。

你甚至不能再使用硬件值来创建键了。虚拟机现在允许人们创建一个“许可”机器的映像,并在他们选择的任何平台上运行它。

如果软件价格昂贵,还有其他解决方案。如果不是,那就给普通黑客制造足够的难度。接受这个事实,即最终会有未授权的副本出现。

如果你的产品很复杂,固有的支持问题将为你创造一些保护。

生成许可密钥的方法有很多,但真正安全的方法很少。这很遗憾,因为对于公司来说,许可证密钥的价值几乎与真正的现金相同。

理想情况下,您希望您的许可密钥具有以下属性:

  1. 只有你的公司能够为你的产品生成许可密钥,即使有人完全逆向工程你的产品(这将会发生,我从经验来说)。如果您真的想控制许可,那么混淆算法或在软件中隐藏加密密钥是不可能的。如果你的产品很成功,那么在发行后的几天内就会有人制作一个密钥生成器。

  2. 一个许可密钥应该只能在一台计算机上使用(或者至少你应该能够非常严格地控制它)

  3. 许可密钥应该很短,并且易于通过电话输入或口述。您不希望每个客户都因为不知道密钥包含“l”还是“1”而呼叫技术支持。您的支持部门将为此感谢您,并且您将在这方面降低成本。

那么如何解决这些挑战呢?

    答案很简单,但在技术上具有挑战性:使用公钥加密的数字签名。您的许可密钥实际上应该是经过签名的“文件”,包含一些有用的数据,并使用您公司的私钥进行签名。签名应该是许可密钥的一部分。产品应使用相应的公钥验证许可密钥。这样,即使某人拥有对产品逻辑的完全访问权,他们也不能生成许可密钥,因为他们没有私有密钥。一个许可密钥看起来像这样:BASE32(CONCAT(DATA, PRIVATE_KEY_ENCRYPTED(HASH(DATA)))) 这里最大的挑战是经典的公钥算法具有很大的签名大小。RSA512有一个1024位签名。您不希望您的许可密钥有数百个字符。 最强大的方法之一是使用椭圆曲线密码学(使用谨慎的实现以避免现有专利)。ECC密钥比RSA密钥短6倍,但强度相同。您可以使用Schnorr数字签名算法(专利于2008年到期-好:))

    等算法进一步减小签名大小
  1. 这可以通过激活产品来实现(Windows就是一个很好的例子)。基本上,对于拥有有效许可密钥的客户,您需要生成一些“激活数据”,这是一个已签名的消息,将计算机的硬件id嵌入为已签名的数据。这通常是在互联网上完成的,但只有一次:产品将许可密钥和计算机硬件id发送到激活服务器,激活服务器将签名消息(也可以使其变得简短,易于通过电话口述)发回。从那一刻起,产品在启动时不再检查许可密钥,而是检查激活数据,这需要计算机相同才能验证(否则,数据将不同,数字签名将无法验证)。请注意,激活数据检查不需要通过Internet进行验证:用已经嵌入到产品中的公钥验证激活数据的数字签名就足够了。

  2. 好吧,只要从你的键中删除多余的字符,如“1”,“l”,“0”,“o”。将许可密钥字符串拆分为字符组。

我们用来生成许可证密钥的c# / .NET引擎现在是开源的:

https://github.com/appsoftware/.NET-Licence-Key-Generator

它基于“部分密钥验证”系统,这意味着只有用于生成密钥的密钥子集必须编译到您的分布式文件中。您自己创建密钥,因此许可证实现对于您的软件是惟一的。

如上所述,如果您的代码可以反编译,那么绕过大多数许可系统就相对容易。

我已经在我公司的软件(c# .net)上实现了基于互联网的一次性激活,它需要一个许可证密钥,该密钥指向存储在服务器数据库中的许可证。软件用密钥攻击服务器,并获得许可信息,然后使用客户端计算机上的一些变量(CPUID和其他不经常更改的东西的组合)生成的RSA密钥在本地加密,然后将其存储在注册表中。

它需要一些服务器端编码,但它对我们来说工作得非常好,当我们扩展到基于浏览器的软件时,我能够使用相同的系统。它也给你的销售人员提供了关于谁,在哪里,什么时候使用软件的很好的信息。任何只在本地处理的许可系统都完全容易被利用,特别是在。net中的反射。但是,正如其他人所说,没有一个系统是完全安全的。

在我看来,如果你不使用基于网络的授权,保护软件就没有任何意义。由于数字版权管理可能引起的头痛,这对已经为此付费的用户来说是不公平的。

我坚信,只有基于公钥密码学的许可系统才是正确的方法,因为您不必将许可证生成所需的基本信息包含到源代码中。

在过去,我曾多次使用Treek's Licensing Library,因为它满足了这个要求,并提供了非常好的价格。它对终端用户和自身使用相同的许可证保护,直到现在还没有人破解它。你也可以在网站上找到避免盗版和破解的好建议。

你可以使用免费的第三方解决方案来解决这个问题,比如Quantum-Key。Net它是免费的,通过paypal为你创建的网络销售页面处理支付,通过电子邮件发放钥匙,并将钥匙锁定到特定的计算机以防止盗版。

你还应该注意混淆/加密你的代码,或者它可以很容易地使用De4dot和. netreflector等软件进行逆向工程。ConfuserEx是一个很好的免费代码混淆器,它使用起来快速简单,比昂贵的替代品更有效。

你应该通过De4Dot和. netreflector运行你完成的软件来逆向工程它,看看黑客会看到什么,如果他们做同样的事情,并确保你没有留下任何重要的代码暴露或未伪装。

你的软件仍然是可以被破解的,但对于那些偶然的破解者来说,这可能足以让他们望而却步,这些简单的步骤也可以防止你的代码被提取和重用。

https://quantum-key.net

ConfuserEx如何使用?< / >

https://github.com/0xd4d/de4dot

https://www.red-gate.com/dynamic/products/dotnet-development/reflector/download

我是Cryptolens软件许可平台背后的开发人员之一,从14岁开始就一直在开发许可系统。在这个回答中,我根据多年来的经验总结了一些建议。

解决这个问题的最佳方法是设置一个许可密钥服务器,应用程序的每个实例都将调用该服务器来验证许可密钥。

许可证密钥服务器的好处

使用许可密钥服务器的优点是:

  1. 您可以随时更新或阻止许可证密钥立即生效。
  2. 每个许可密钥可以被锁定到一定数量的机器上(这有助于防止用户在线发布许可密钥供其他人使用)。

注意事项

虽然在线验证许可证可以让您更好地控制应用程序的每个实例,但internet连接并不总是存在(特别是如果您的目标是大型企业),因此我们需要另一种方式来执行许可证密钥验证。

解决方案是始终使用公钥加密系统(如RSA或ECC)对来自服务器的许可密钥响应进行签名(如果计划在嵌入式系统上运行,可能更好)。您的应用程序应该只有公钥来验证许可密钥响应。

因此,在没有互联网连接的情况下,您可以使用之前的许可密钥响应。确保在响应中存储日期机标识符,并检查它不是太旧(例如。您允许用户离线最多30天,等等),并且许可密钥响应属于正确的设备。

请注意你应该总是检查许可密钥响应的证书,即使你连接到互联网),以确保它没有被改变,因为它离开服务器(这仍然必须做,即使你的API到许可密钥服务器使用https)

保护秘密算法

大多数。net应用程序都可以很容易地进行反向工程(微软提供了一个反汇编程序来获得IL代码,一些商业产品甚至可以检索源代码,例如。c#)。当然,您总是可以混淆代码,但它永远不会是100%安全的。

在大多数情况下,任何软件许可解决方案的目的都是帮助诚实的人变得诚实(即愿意付费的诚实用户在试用期满后不会忘记付费,等等)。

然而,您可能仍然有一些您不想泄露给公众的代码(例如。预测股票价格的算法等)。在这种情况下,唯一的方法是创建一个API端点,你的应用程序将在每次执行方法时调用它。它需要互联网连接,但它确保你的秘密代码永远不会被客户端机器执行。

实现

如果你不想自己实现所有东西,我建议你看看本教程 (Cryptolens的一部分)

我通过将我的程序与一个不和谐的服务器连接来解决这个问题,它在一个特定的聊天中检查用户输入的产品密钥是否存在并且仍然有效。通过这种方式获得产品密钥,用户将被迫破解不和谐,这是非常困难的。

我知道这是一个老问题,但我在为我的一个应用程序重新编写许可流程时引用了这个问题。

在阅读了大量的意见并依靠过去的许可代码经验后,我想出了这个过程。

public static class LicenseGenerator
{
private static string validChars = "ACEFHJKMNPRSTUVWXYZ234579";
private static Random rnd = new Random(Guid.NewGuid().GetHashCode());


/// <summary>
/// Generate a license code
/// </summary>
/// <param name="length">length of each phrase</param>
/// <param name="number">number of phrases separated by a '-'</param>
/// <returns></returns>
public static string GetNewCode(int length, int number)
{
string license = string.Empty;


for (int numberOfPhrases = 0; numberOfPhrases < number; numberOfPhrases++)
{
license += getPhrase(length);
if (numberOfPhrases < number)
license += "-";
}


return license.TrimEnd('-');
}


/// <summary>
/// generate a phrase
/// </summary>
/// <param name="length">length of phrase</param>
/// <returns></returns>
private static string getPhrase(int length)
{
string phrase = string.Empty;


for (int loop = 0; loop < length; loop++)
{
phrase += validChars[rnd.Next(validChars.Length)];
}


return phrase;
}
}

你真的不想提供一个有相似字母的代码;当最终用户输入时,它会造成混乱。像6和G, B和8,L, I和1。当然,如果你真的想要它们,你可以随时把它们加回来……上面的代码将使用"validChars"中的字符生成类似xxxx-xxxx-xxxx-xxxx的许可证。调用GetNewCode(4,4)将返回与上面类似的代码。

我使用Azure函数注册然后验证代码。当我的应用程序注册代码时,它会生成一个加密散列,其中包含安装、设备和/或用户独有的内容。它被提供给注册函数,并与密钥一起存储在Azure的DB中。

验证重新生成密钥,并向其提供许可代码、IP地址(在我的例子中,IP地址不会改变,如果改变了,那么无论如何都需要更新)和重新生成的散列,然后Azure函数在应用程序获得许可时返回。我确实存了一个“临时的”;在他们的服务器上的键,允许应用程序运行一段时间而不回复。

当然,我的应用程序必须在网络上,它的工作无论如何。

因此,最终结果是一个供最终用户输入的简单密钥,以及在后端管理许可证的简单流程。如果需要,我还可以使许可证无效。