许可证密钥是作为反盗版措施的事实标准。老实说,这让我觉得(in)Security Through Obscurity,虽然我真的不知道许可证密钥是如何生成的。什么是许可证密钥生成的好(安全)示例?他们使用什么加密原语(如果有的话)?是消息摘要吗?如果是这样,他们会散列什么数据?开发人员采用什么方法使破解者难以构建自己的密钥生成器?密钥生成器是如何制造的?
11 回答
对于老式的 CD 密钥,只需制定一个算法,使 CD 密钥(可以是任何字符串)易于生成和验证,但有效 CD 密钥与无效 CD 的比率-keys 是如此之小,以至于随机猜测 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 密钥算法和所有其他版权保护。
真正正确的做法:
对于在线服务,生活要简单一些,因为即使使用二进制文件,您也需要通过他们的服务器进行身份验证才能使用它(例如,拥有一个 WoW 帐户)。魔兽世界的 CD-key 算法 - 例如,在购买游戏卡时使用 - 可能看起来像这样:
- 生成一个非常大的密码安全随机数。
- 将其存储在我们的数据库中并打印在卡片上。
然后,当有人输入游戏时间卡号码时,检查它是否在数据库中,如果是,则将该号码与当前用户相关联,这样就不能再使用它了。
对于在线服务,没有理由不使用上述方案;使用其他任何东西都会导致问题。
当我最初写这个答案时,假设问题是关于许可证密钥的“离线”验证。大多数其他答案都涉及在线验证,这更容易处理(大部分逻辑都可以在服务器端完成)。
使用离线验证,最困难的事情是确保您可以生成大量唯一的许可证密钥,并且仍然保持一个不易被破坏的强大算法(例如简单的校验位)
我对数学不是很精通,但让我印象深刻的是,做到这一点的一种方法是使用绘制图形的数学函数
绘制的线可以具有(如果您使用足够精细的频率)数千个唯一点,因此您可以通过在该图上选择随机点并以某种方式对值进行编码来生成键
作为示例,我们将绘制此图,选择四个点并将其编码为字符串“0,-500;100,-300;200,-100;100,600”
我们将使用已知且固定的密钥(非常弱,但它有目的)加密字符串,然后通过Base32转换结果字节以生成最终密钥
然后应用程序可以反转这个过程(base32 到实数,解密,解码点),然后检查每个点是否在我们的秘密图上。
它的代码量相当小,可以生成大量唯一且有效的密钥
然而,它是非常安全的默默无闻。任何花时间反汇编代码的人都可以找到图形功能和加密密钥,然后模拟密钥生成器,但它可能对减缓随意盗版非常有用。
查看有关部分密钥验证的文章,其中涵盖以下要求:
许可证密钥必须足够容易输入。
我们必须能够在退款或使用被盗信用卡购买的情况下将许可证密钥列入黑名单(撤销)。
没有“打电话回家”来测试密钥。虽然这种做法越来越流行,但作为用户我还是不欣赏,所以不会要求我的用户忍受。
破解者应该不可能反汇编我们发布的应用程序并从中生成一个有效的“keygen”。这意味着我们的应用程序不会完全测试密钥以进行验证。只有一些关键是要测试的。此外,应用程序的每个版本都应测试密钥的不同部分,因此基于早期版本的假密钥将无法在我们软件的后续版本中使用。
重要提示:合法用户不应意外输入无效的密钥,该密钥似乎可以工作,但由于印刷错误而在未来的版本中失败。
我对人们实际生成 CD 密钥的操作没有任何经验,但是(假设您不想走在线激活的道路)这里有几种制作密钥的方法:
要求该数字可以被(例如)17 整除。如果您可以访问许多键,那么猜测很简单,但大多数潜在的字符串将是无效的。类似的情况是要求密钥的校验和与已知值匹配。
要求键的前半部分与已知值连接时,向下散列到键的后半部分。更好,但该程序仍然包含生成密钥以及验证它们所需的所有信息。
通过加密(使用私钥)已知值 + 随机数来生成密钥。这可以通过使用相应的公钥解密并验证已知值来验证。该程序现在有足够的信息来验证密钥而无法生成密钥。
这些仍然都容易受到攻击:程序仍然存在并且可以被修补以绕过检查。更聪明的做法可能是使用我的第三种方法中的已知值来加密程序的一部分,而不是将值存储在程序中。这样,您必须在解密程序之前找到密钥的副本,但它仍然很容易在解密后被复制,并且让一个人获取他们的合法副本并使用它来使其他人能够访问该软件。
CD-Keys 对于任何非联网的东西都不是很安全,所以从技术上讲,它们不需要安全地生成。如果您在.net 上,您几乎可以使用 Guid.NewGuid()。
如今,它们的主要用途是多人游戏组件,服务器可以在其中验证 CD 密钥。为此,生成它的安全性并不重要,因为它归结为“查找传入的任何内容并检查其他人是否已经在使用它”。
话虽如此,您可能希望使用算法来实现两个目标:
- 有某种校验和。这允许您的安装程序显示“密钥似乎无效”消息,仅用于检测拼写错误(在安装程序中添加这样的检查实际上意味着编写密钥生成器是微不足道的,因为黑客拥有他需要的所有代码。没有检查并仅依赖服务器端验证会禁用该检查,冒着惹恼您的合法客户的风险,他们不明白为什么服务器不接受他们的 CD 密钥,因为他们不知道拼写错误)
- 使用有限的字符子集。尝试输入 CD 密钥并猜测“这是 8 还是 B?1 还是 I?Q 或 O 还是 0?” - 通过使用非模棱两可的字符/数字的子集,您可以消除这种混淆。
话虽如此,你仍然需要一个大的分布和一些随机性,以避免盗版者简单地猜测一个有效的密钥(这在你的数据库中是有效的,但仍然在商店货架上的一个盒子里)并搞砸碰巧购买那个盒子的合法客户.
密钥系统必须具有几个属性:
- 很少有密钥必须是有效的
- 即使给定用户拥有的一切,也不能导出有效密钥。
- 一个系统上的有效密钥不是另一个系统上的有效密钥。
- 其他
应该为您提供这些的一种解决方案是使用公钥签名方案。从“系统哈希”开始(比如抓取任何 NIC 上的 mac,排序和 CPU-ID 信息,加上其他一些东西,将它们连接在一起并获取结果的 MD5(你真的不想成为如果您不需要处理个人身份信息))附加 CD 的序列号并拒绝启动,除非某些注册表项(或某些数据文件)具有该 blob 的有效签名。用户通过将 blob 发送给您来激活程序,然后您将签名寄回。
潜在的问题包括您提供几乎任何东西的签名,因此您需要假设有人会运行选定的纯文本和/或选定的密文攻击。这可以通过检查提供的序列号并拒绝处理来自无效请求的请求以及拒绝处理来自给定序列号的超过给定数量的查询来缓解(比如每年 2 次)
我应该指出一些事情:首先,一个熟练而坚定的攻击者将能够绕过他们可以不受限制地访问的部分(即CD 上的所有内容)中的任何和所有安全性,您可以在该帐户上做的最好的事情是使获得非法访问比获得合法访问更难。其次,我不是专家,所以这个提议的方案可能存在严重缺陷。
如果您不是特别在意密钥的长度,那么一种经过验证且真实的方法是使用公钥和私钥加密。
本质上具有某种随机数和固定签名。
例如:0001-123456789
其中 0001 是您的 nonce,而 123456789 是您的固定签名。
然后使用您的私钥对其进行加密以获得您的 CD 密钥,类似于:ABCDEF9876543210
然后将公钥与您的应用程序一起分发。公钥可用于解密 CD 密钥“ABCDEF9876543210”,然后您可以验证其固定签名部分。
这样可以防止有人猜测随机数 0002 的 CD 密钥是什么,因为他们没有私钥。
唯一的主要缺点是,当使用 1024 位大小的私钥/公钥时,您的 CD 密钥会很长。您还需要选择足够长的随机数,以免加密少量信息。
好的一面是,这种方法无需“激活”即可工作,您可以使用电子邮件地址或被许可人姓名等内容作为随机数。
我意识到这个答案对聚会晚了大约 10 年。
一个好的软件许可证密钥/序列号生成器不仅仅包含一串随机字符或来自某个曲线生成器的值。使用有限的字母数字字母表,可以将数据嵌入到包含各种有用信息的短字符串(例如 XXXX-XXXX-XXXX-XXXX)中,例如:
- 创建日期或许可证到期日期
- 产品 ID、产品分类、主要和次要版本号
- 自定义位,如硬件哈希
- 每个用户的哈希校验和位(例如,用户输入他们的电子邮件地址以及许可证密钥,这两条信息都用于计算/验证哈希)。
然后对许可证密钥数据进行加密,然后使用有限的字母数字字母表对其进行编码。对于在线验证,许可证服务器持有解密信息的秘密。对于离线验证,软件本身包含解密密钥以及解密/验证代码。显然,离线验证意味着该软件对于制作注册机的人来说并不安全。
创建许可证密钥最困难的部分可能是弄清楚如何将尽可能多的数据塞进尽可能少的字节中。请记住,用户将手动输入他们的许可证密钥,因此每一位都很重要,用户不想输入非常长、复杂的字符串。16 到 25 个字符的许可证密钥是最常见的,并平衡了可以放置多少数据进入密钥与用户对输入密钥解锁软件的容忍度。将字节分割成比特块允许包含更多信息,但确实增加了生成器和验证器的代码复杂性。
加密是一个复杂的话题。一般来说,像 AES 这样的标准加密算法的块大小与保持许可证密钥长度较短的目标不一致。因此,大多数制作自己的许可证密钥的开发人员最终会编写自己的加密算法(这种活动经常被劝阻)或根本不加密密钥,这保证有人会编写密钥生成器。可以说,良好的加密很难做到正确,对 Feistel 网络和现有密码如何工作的充分理解是先决条件。
验证密钥是对字符串进行解码和解密、验证哈希/校验和、检查数据中的产品 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/
完全披露:我是许可证服务器和演示站点软件的作者。
还有一些 DRM 行为将多个步骤合并到流程中。最著名的示例之一是 Adobe 验证其 Creative Suite 安装的方法之一。使用这里讨论的传统 CD Key 方法,然后调用 Adobe 的支持热线。将 CD 密钥提供给 Adobe 代表,他们会返回一个供用户使用的激活号。
然而,尽管被分解成多个步骤,但它仍会成为与正常过程相同的破解方法的牺牲品。用于创建与原始 CD 密钥核对的激活密钥的过程很快被发现,并制作了包含这两个密钥的生成器。
但是,这种方法仍然存在,作为没有互联网连接的用户验证产品的一种方式。展望未来,随着互联网接入变得无处不在,很容易看出这些方法将如何被淘汰。
所有 CD 仅复制保护算法都给诚实的用户带来不便,同时不提供任何针对盗版的保护。
“盗版者”只需要访问一张合法的 cd 及其访问代码,然后他就可以制作 n 份并分发它们。
无论您制作代码的密码安全程度如何,您都需要以纯文本形式随 CD 一起提供,否则合法用户无法激活该软件。
大多数安全方案包括用户向软件供应商提供将运行该软件的机器的一些详细信息(cpu 序列号、mac 地址、IP 地址等),或者要求在线访问以在供应商网站上注册软件,并且作为回报,您会收到一个激活令牌。第一个选项需要大量的手动管理,并且仅对于非常高价值的软件才值得,第二个选项可能会被欺骗,如果您的网络访问权限有限或者您被困在防火墙后面,这绝对是令人恼火的。
总的来说,与客户建立信任关系要容易得多!
您可以使用它在您的软件项目中非常轻松地使用和实施 Secure Licensing API (您需要从https://www.systemsoulsoftwares.com/下载桌面应用程序以创建安全许可证)
- 根据系统硬件(CPU、主板、硬盘)为客户端软件创建唯一的 UID(UID 充当该唯一系统的私钥)
- 允许非常轻松地将加密的许可证字符串发送到客户端系统,它验证许可证字符串并仅在该特定系统上工作
- 此方法允许软件开发人员或公司存储有关软件/开发人员/分销商服务/功能/客户端的更多信息
- 它可以控制锁定和解锁客户端软件功能,从而节省开发人员为具有更改功能的相同软件制作更多版本的时间
- 它也关心试用版的任何天数
- 它通过在注册期间在线检查日期时间来保护许可证时间表
- 它向开发人员解锁所有硬件信息
- 它具有开发人员可以在每个许可过程中访问的所有预构建和自定义功能,以制作更复杂的安全代码