License keys are the defacto-standard as an anti-piracy measure. To be honest, this strikes me as (in)Security Through Obscurity, although I really have no idea how license keys are generated. What is a good (secure) example of license key generation? What cryptographic primitive (if any) are they using? Is it a message digest? If so, what data would they be hashing? What methods do developers employ to make it difficult for crackers to build their own key generators? How are key generators made?


当前回答

我意识到这个答案晚了10年。

一个好的软件许可密钥/序列号生成器不仅仅由一串随机字符或某个曲线生成器的值组成。使用有限的字母数字字母表,数据可以嵌入到一个短字符串中(例如XXXX-XXXX-XXXX-XXXX),其中包括各种有用的信息,例如:

创建日期或license过期日期 产品ID、产品分类、主要版本号和次要版本号 自定义位,如硬件哈希 每个用户哈希校验和位(例如,用户输入他们的电子邮件地址和许可密钥,这两个信息都用于计算/验证哈希)。

然后对许可证密钥数据进行加密,然后使用有限的字母数字字母进行编码。对于在线验证,许可证服务器保存解密信息的秘密。对于脱机验证,解密秘密连同解密/验证代码一起包含在软件本身中。很明显,离线验证意味着软件不安全,无法防止有人输入密钥。

Probably the hardest part about creating a license key is figuring out how to cram as much data as possible into as few bytes as possible. Remember that users will be entering in their license keys by hand, so every bit counts and users don't want to type extremely long, complex strings in. 16 to 25 character license keys are the most common and balance how much data can be placed into a key vs. user tolerance for entering the key to unlock the software. Slicing up bytes into chunks of bits allows for more information to be included but does increase code complexity of both the generator and validator.

Encryption is a complex topic. In general, standard encryption algorithms like AES have block sizes that don't align with the goal of keeping license key lengths short. Therefore, most developers making their own license keys end up writing their own encryption algorithms (an activity which is frequently discouraged) or don't encrypt keys at all, which guarantees that someone will write a keygen. Suffice it to say that good encryption is hard to do right and a decent understanding of how Feistel networks and existing ciphers work are prerequisites.

验证密钥就是解码和解密字符串、验证散列/校验和、检查数据中的产品ID和主要版本号和次要版本号、验证许可证没有过期,以及执行其他需要执行的检查。

编写密钥生成器就是要知道许可密钥由什么组成,然后生成与原始密钥生成器生成的相同的输出。如果用于许可证密钥验证的算法包含在软件中并由软件使用,那么只需创建与验证过程相反的软件。

为了了解整个过程是什么样子的,下面是我最近写的一篇关于选择许可密钥长度、数据布局、加密算法和最终编码方案的博客文章:

https://cubicspot.blogspot.com/2020/03/adventuring-deeply-into-software-serial.html

从博客文章中可以看到一个实用的、真实的密钥生成器和密钥验证器的实现:

https://github.com/cubiclesoft/php-misc/blob/master/support/serial_number.php

上面类的文档:

https://github.com/cubiclesoft/php-misc/blob/master/docs/serial_number.md

可以在这里找到一个生产就绪的开源许可服务器,它使用上面的序列号代码生成和管理许可密钥:

https://github.com/cubiclesoft/php-license-server

上述许可服务器支持在线和离线验证模式。一个软件产品可能只从在线验证开始存在。当软件产品准备退役并且不再受支持时,它可以很容易地转移到离线验证,一旦用户升级到切换到离线验证的软件的最后一个版本,所有现有的密钥将继续工作。

在这里可以找到如何将上述许可证服务器集成到网站中以销售软件许可证和可安装的演示应用程序的现场演示(网站和演示应用程序都是开源的):

https://license-server-demo.cubiclesoft.com/

完全公开:我是许可证服务器和演示站点软件的作者。

其他回答

对于老式的CD键来说,这只是一个容易生成和验证CD键(可以是任何字符串)的算法的问题,但是有效CD键与无效CD键的比例是如此之小,以至于随机猜测CD键不太可能得到有效的CD键。

错误的做法:

《星际争霸》和《半条命》都使用了相同的校验和,即第13个数字验证了前12个数字。因此,您可以为前12位输入任何数字,并猜测第13位(只有10种可能),从而得到臭名昭著的1234-56789-1234

验证算法是公开的,看起来像这样:

x = 3;
for(int i = 0; i < 12; i++)
{
    x += (2 * x) ^ digit[i];
}
lastDigit = x % 10;

正确的方法

Windows XP收集了相当多的信息,对其进行加密,然后将字母/数字编码放在贴纸上。这允许MS同时验证您的密钥并获得产品类型(家庭、专业等)。此外,它需要在线激活。 完整的算法相当复杂,但在德国发表的这篇(完全合法的!)论文中很好地概述了它。

当然,无论你做什么,除非你提供的是在线服务(如《魔兽世界》),任何类型的版权保护都只是一种拖延:不幸的是,如果这是一款有价值的游戏,就会有人破坏(或至少绕过)CD-key算法和所有其他版权保护。

真正正确的做法:

对于在线服务来说,情况要简单一些,因为即使使用二进制文件,你也需要通过服务器的身份验证才能使用它。拥有一个WoW账号)。魔兽世界的CD-key算法——例如,在购买游戏卡时使用——可能看起来像这样:

生成一个非常大的加密安全随机数。 储存在我们的数据库中,并打印在卡片上。 然后,当有人输入游戏时间卡号时,检查它是否在数据库中,如果是,将该号码与当前用户关联,以便它永远不会再被使用。

对于网上服务,没有理由不使用上述方案;使用其他任何方法都可能导致问题。

所有的CD拷贝保护算法给诚实的用户带来不便,同时没有提供任何防止盗版的保护。

“盗版者”只需要获得一张合法的cd及其访问代码,他就可以制作n份拷贝并分发它们。

无论代码的加密安全性如何,都需要以明文形式提供CD,否则合法用户无法激活该软件。

Most secure schemes involve either the user providing the software supplier with some details of the machine which will run the software (cpu serial numbers, mac addresses, Ip address etc.), or, require online access to register the software on the suppliers website and in return receive an activitation token. The first option requires a lot of manual administration and is only worth it for very high value software, the, second option can be spoofed and is absolutly infuriating if you have limited network access or you are stuck behind a firewall.

总的来说,与客户建立信任关系要容易得多!

当我最初写下这个答案时,假设这个问题是关于许可证密钥的“离线”验证。大多数其他答案都涉及在线验证,这明显更容易处理(大部分逻辑可以在服务器端完成)。

使用离线验证,最困难的事情是确保你可以生成大量唯一的许可密钥,并且仍然保持一个不容易被破坏的强大算法(例如一个简单的检查数字)。

我不是很精通数学,但我想到了一种方法,那就是使用一个数学函数来绘制图形

绘制的线可以有(如果使用足够精确的频率)数千个唯一点,因此可以通过在图上随机选择点并以某种方式编码值来生成键

例如,我们将绘制这张图,选择四个点并将其编码为字符串“0,-500;100,-300;200,-100;100,600”

我们将使用一个已知的固定密钥加密字符串(非常弱,但它是有目的的),然后通过Base32转换结果字节以生成最终密钥

然后应用程序可以反转这个过程(从base32到实数,解密,解码这些点),然后检查这些点是否在我们的秘密图上。

这是一个相当少的代码,将允许生成大量的唯一和有效的密钥

然而,它是非常安全的默默无闻。任何花时间分解代码的人都能够找到绘图函数和加密密钥,然后模拟密钥生成器,但它可能对于减缓随意的盗版非常有用。

密钥系统必须具有以下几个属性:

只有很少的键是有效的 即使给定用户拥有的一切,有效的键也必须是不可派生的。 一个系统上的有效密钥在另一个系统上不是有效密钥。 其他人

One solution that should give you these would be to use a public key signing scheme. Start with a "system hash" (say grab the macs on any NICs, sorted, and the CPU-ID info, plus some other stuff, concatenate it all together and take an MD5 of the result (you really don't want to be handling personally identifiable information if you don't have to)) append the CD's serial number and refuse to boot unless some registry key (or some datafile) has a valid signature for the blob. The user activates the program by shipping the blob to you and you ship back the signature.

潜在的问题包括,你提供的签名几乎是任何东西,所以你需要假设有人会运行选定的纯文本和/或选定的密文攻击。可以通过检查提供的序列号并拒绝处理来自无效序列号的请求,以及拒绝在一段时间内(例如每年2次)处理来自给定s/n的超过给定数量的查询来缓解这一问题。

我应该指出几件事:首先,一个熟练和坚定的攻击者将能够绕过他们拥有无限制访问权限的部分(即CD上的所有内容)的任何和所有安全性,您对该帐户所能做的最好的事情是使其更难获得非法访问而不是获得合法访问。其次,我不是专家,所以这个提议的方案可能存在严重的缺陷。

我意识到这个答案晚了10年。

一个好的软件许可密钥/序列号生成器不仅仅由一串随机字符或某个曲线生成器的值组成。使用有限的字母数字字母表,数据可以嵌入到一个短字符串中(例如XXXX-XXXX-XXXX-XXXX),其中包括各种有用的信息,例如:

创建日期或license过期日期 产品ID、产品分类、主要版本号和次要版本号 自定义位,如硬件哈希 每个用户哈希校验和位(例如,用户输入他们的电子邮件地址和许可密钥,这两个信息都用于计算/验证哈希)。

然后对许可证密钥数据进行加密,然后使用有限的字母数字字母进行编码。对于在线验证,许可证服务器保存解密信息的秘密。对于脱机验证,解密秘密连同解密/验证代码一起包含在软件本身中。很明显,离线验证意味着软件不安全,无法防止有人输入密钥。

Probably the hardest part about creating a license key is figuring out how to cram as much data as possible into as few bytes as possible. Remember that users will be entering in their license keys by hand, so every bit counts and users don't want to type extremely long, complex strings in. 16 to 25 character license keys are the most common and balance how much data can be placed into a key vs. user tolerance for entering the key to unlock the software. Slicing up bytes into chunks of bits allows for more information to be included but does increase code complexity of both the generator and validator.

Encryption is a complex topic. In general, standard encryption algorithms like AES have block sizes that don't align with the goal of keeping license key lengths short. Therefore, most developers making their own license keys end up writing their own encryption algorithms (an activity which is frequently discouraged) or don't encrypt keys at all, which guarantees that someone will write a keygen. Suffice it to say that good encryption is hard to do right and a decent understanding of how Feistel networks and existing ciphers work are prerequisites.

验证密钥就是解码和解密字符串、验证散列/校验和、检查数据中的产品ID和主要版本号和次要版本号、验证许可证没有过期,以及执行其他需要执行的检查。

编写密钥生成器就是要知道许可密钥由什么组成,然后生成与原始密钥生成器生成的相同的输出。如果用于许可证密钥验证的算法包含在软件中并由软件使用,那么只需创建与验证过程相反的软件。

为了了解整个过程是什么样子的,下面是我最近写的一篇关于选择许可密钥长度、数据布局、加密算法和最终编码方案的博客文章:

https://cubicspot.blogspot.com/2020/03/adventuring-deeply-into-software-serial.html

从博客文章中可以看到一个实用的、真实的密钥生成器和密钥验证器的实现:

https://github.com/cubiclesoft/php-misc/blob/master/support/serial_number.php

上面类的文档:

https://github.com/cubiclesoft/php-misc/blob/master/docs/serial_number.md

可以在这里找到一个生产就绪的开源许可服务器,它使用上面的序列号代码生成和管理许可密钥:

https://github.com/cubiclesoft/php-license-server

上述许可服务器支持在线和离线验证模式。一个软件产品可能只从在线验证开始存在。当软件产品准备退役并且不再受支持时,它可以很容易地转移到离线验证,一旦用户升级到切换到离线验证的软件的最后一个版本,所有现有的密钥将继续工作。

在这里可以找到如何将上述许可证服务器集成到网站中以销售软件许可证和可安装的演示应用程序的现场演示(网站和演示应用程序都是开源的):

https://license-server-demo.cubiclesoft.com/

完全公开:我是许可证服务器和演示站点软件的作者。