生成产品激活序列号

7

首先,这不是一个关于为其他产品生成序列号的问题。我想要“破解”其他产品。

以下是我的要求:

  • 我希望生成一个标准的序列号:AILU7-ABCDE-54321-1234-AFCK-17UDF。
  • 我需要一些流程来验证该序列号是否“有效”——这部分必须非常复杂。例如,如果所有数字加起来的值大于X,那么我就可以接受,但如果有解决这个复杂性的解决方案,我很乐意使用它们。
  • 验证序列号的过程不能是服务器端的。也就是说,我不能向外部Web服务器发出请求来验证序列号是否有效。
  • 我需要一种从序列号中提取元数据的方法。也就是说,在验证序列号正确之后,我需要能够从中读出一些值:“用户限制”,“到期日期”等等。
  • 通过ASP.NET MVC 3应用程序进行序列号验证。序列号的生成一定要这样做。
我不是在寻找一个能够实现所有这些要求的万能方法,而是想要一些文档或现有库的链接来帮助我入门。我看到的唯一一个库是XHEO DeployLX库,但它对我的需求来说过于复杂了。
请问您能否提供任何能指导我正确方向的信息?

你在SO上看到这个链接了吗:http://stackoverflow.com/questions/4583630/serial-numbers-generation-without-user-data - Simon Mourier
4
我不确定您想实现的目标是否可行,例如将公司名称嵌入到短字符串中,如果可能的话,这将非常困难。如果您需要额外的元数据,也许应该考虑使用许可文件模型,或者在某个地方存储键->元数据映射。 - Ian
@Ian - 我完全同意。我只需要关于如何开始使用这个模型的信息。目前,密码学对我来说是陌生的。 - Bryan Ray
@Ian - 同意。从短字符串中验证公司名称或其他任何内容肯定是可能的,但编码它将会更加困难。这是一个压缩问题。 - Bobson
@Ian,你能提供一些关于所提到的“许可文件模型”的链接或信息吗?我的谷歌搜索技巧在这方面没有帮助。 - Bryan Ray
1
@BryanRay:实际上我不知道有没有任何例子(这是我想看看是否有常见的方法)。这个想法是你有一个文件,其中包含所有的元信息(公司名称、机器信息等),以及一个生成的ID。然后由提供者使用私钥对其进行哈希处理。应用程序将使用公钥验证文件是否已被修改,通过检查哈希值,然后可以从中读取所有许可证信息。 - Ian
3个回答

5

这个链接很棒。我会从那里开始。非常感谢你,维克托。 - Bryan Ray
我几乎希望我的软件需要这种保护,这样我就可以实现它。听起来设计起来有点有趣。 - Bobson

4

0

使用序列号时需要考虑一些事情。

在我的搜索中,我看到了一些链接,指向使用简单的Guid.NewGuid();方法,然后对字符串进行一些转换,以制作自定义样式的序列号。这很容易做到,但是将责任放在您产品所有者身上,需要在数据库中跟踪序列号,并且在一天结束时,有可能会有人通过使用Guid.NewGuid();自己找到有效的序列号。如果地球上的每个人都开始同时生成Guids,则碰撞机会变得非常大。

有一种解决方案可以通过在Guid.NewGuid();之上使用更复杂的算法来使碰撞事件变得不太可能。

为此,我倾向于使用:

  1. Guid.NewGuid();(仅前16个字符,减去-(连字符)
  2. 一个不断增加或更改的值。(Nonce)(int将起作用:i++等)
  3. 您将在网络中保持私有和安全的秘密盐。
  4. 难度因素:从比特币借用这个原则。

好的,让我们想象一下我正在从GUID中获取前16位数字。 然后将其与Nonce和秘密盐结合, 然后使用SHA256从这些值中派生哈希。 然后,我可以使用难度因子来确定哈希是否以我所需的0或其他字符开头。

例如:如果哈希值有六个0作为前缀,则我会保存所有数据,因为我刚刚找到了一个相当安全的序列号。

当我说安全时,我的意思是我已经找到了一个序列号,当与产品密钥(Nonce)组合并与秘密盐一起使用时,它会产生符合我的生产标准的哈希。

以下是一些示例代码-非常粗略,因为我很无聊。

想法是您的应用程序可以将产品密钥和序列号发送到激活服务器。服务器知道秘密盐。然后,它返回true或false以确定生成的哈希是否符合安全要求。 如果不符合:则序列号无效,或者不适用于提供的密钥。 如果具有所需的0:则为有效序列号。

    Guid theGuid;
    string Hash = "";
    int iAccess = 0;
    string PrivateSalt = "Alpha";
    string SourceString = "";
    string guidString;
    while (true)
    {
        theGuid = Guid.NewGuid();
        guidString = theGuid.ToString().Replace("-", "").Substring(0,16);
        SourceString = guidString + "|" + iAccess.ToString() + "|" + PrivateSalt;
        byte[] data = Encoding.Default.GetBytes(SourceString);
        Hash = Crypto.GenerateSHA256(data);
        if (Hash.StartsWith(GetDiff()))
        {
            break;
        }

        iAccess++;
    }
    Console.WriteLine(SourceString+" Gives hash "+Hash);
    string s1, s2, s3, s4;
    s1 = guidString.Substring(0, 4);
    s2 = guidString.Substring(4, 4);
    s3 = guidString.Substring(8, 4);
    s4 = guidString.Substring(12, 4);
    string serial = s1 + "-" + s2 + "-" + s3 + "-" + s4;

    Console.WriteLine(serial + " :" + SourceString + " Gives hash " + Hash);

GetDiff() 基本上只是一个字符串:"000000";

这个方法的示例输出如下:

d9c9-f6f0-45be-427a :d9c9f6f045be427a|15135|Alpha Gives hash    000000f718f69c8389d496e01d1e992946fe1b8cf72bc4200a7a2b800b40aa0a
fe49-70b9-08d8-40df :fe4970b908d840df|9096414|Alpha Gives hash  000000e29cfccfb54d1e7edc816feb084f1a2cd11a20c3132a965f9048fc9bf4
7f58-0636-c853-4f0a :7f580636c8534f0a|12297217|Alpha Gives hash 0000007bb44f39a964bbe985885451c3dc0e037fcd12951261404e48819bf89b
6f65-82d3-d95b-4882 :6f6582d3d95b4882|15064854|Alpha Gives hash 000000f1a3bed79e441108cfd26d8733d3fc10f5cd66d234ed35fe2b769663a3
edee-b8b7-9f6f-40ab :edeeb8b79f6f40ab|17782415|Alpha Gives hash 000000b70b96e7b008a96a860efc572fe868154ae81e67b9397249a51f2db71c
0948-4bb3-7de4-4054 :09484bb37de44054|21105690|Alpha Gives hash 000000ec7317eccd5fd9bb701759a2b0e77d37099347d9d665f4b492a69ca3ec
bbf5-5119-bf4e-463c :bbf55119bf4e463c|21715642|Alpha Gives hash 000000a134c886d01606da83cd5e8f672fddb6aa061968e9f08202c781514b16
80f6-c9c5-0ddf-436d :80f6c9c50ddf436d|26450310|Alpha Gives hash 00000092305b2956381c23dacba5b8ff9a37ab994148b37677732dc2a0650386
0a4f-143b-b5f5-48ca :0a4f143bb5f548ca|33691865|Alpha Gives hash 00000054ecdae57c6ec686b6084faf68ae49a78f7c07bbe8e51357d76de63870

你可以通过在前缀中添加更多的0来增加难度。这意味着查找串行组合将需要更长时间,但也使其更安全。

显然,您会将这些数据组合存储在某个地方,以便在激活期间,您可以比较序列代码和产品密钥(Nonce)。

在我的示例中:我使用序列密钥(16位数字)、递增整数和单词Alpha作为秘密盐。

这使得生成序列密钥变得缓慢且需要大量的CPU计算,但使验证它们非常快速。

IsSerialValid("edee-b8b7-9f6f-40ab", 17782415);

public bool IsSerialValid(string serialCode, int ProductCode)
        {
            string SourceString = serialCode.Replace("-", "") + "|" + ProductCode.ToString() + "|" + "Alpha";
            byte[] data = Encoding.Default.GetBytes(SourceString);
            string Hash = Crypto.GenerateSHA256(data);
            if (Hash.StartsWith(GetDiff()))
            {
                return true;
            }
            return false;
        }

秘密盐可以是一个代码短语,它映射到您可能正在开发的不同产品。这使您可以在多个产品线上重复使用产品密钥(Nonce)值。


验证不起作用,总是返回false,因为在验证中使用的源字符串与生成产品代码部分时使用的不同,所以它们将不同。 - Henka Programmer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接