使用C# Win Forms Setup从唯一的机器密钥生成许可证密钥

8
我在Visual Studio 2010中开发了一个C# win forms应用程序,并使用系统的cpuId、biosId和diskId生成一个机器相关的密钥,如下图所示: key 现在,在安装设置中,我只需要获取一个密钥输入区域,如下图所示: enter image description here 我想在序列号输入区域上方显示为特定系统创建的机器密钥。
我的需求是最终用户或软件购买者给我打电话并提供机器密钥,然后我将使用该密钥计算一个密钥并发送回客户端或购买者。
这是我的第一个安装设置项目,所以我完全不了解这个事情。非常感谢您的帮助。

@AccessDenied 我想在上述表单中添加一个单独的字段来显示机器密钥,并在插入序列号时进行验证。 - Ashok
您可以附加委托,当序列文本框中的任何更改出现时,将检查密钥在线。将方法ValidateSerialNumber注册到所有复选框事件。 - h__
1
我建议不要打扰用户处理这些细节,而是利用时间开发一个Web服务,接收这些信息,将它们存储在数据库中等待您的批准,并发送一个包含解锁应用程序所需密钥的文件。 - Steve
1
@Ashok_Karale 我认为这是一个相当复杂和相关的问题,它值得写一篇关于生成机器相关密钥的单独文章。 - user2604650
1
正如@AccessDenied在他的答案中所示,实际上您有两个问题。重复:如何将其他自定义窗口添加到VS设置项目UI流程中如何快速在C#中获取硬件ID?生成唯一硬件ID的可靠方法。请尝试使用搜索。 :-) - CodeCaster
显示剩余2条评论
3个回答

4
我想把你的问题分成两部分:
创建一个带有必填字段或控件的UI,用户可以在其中提供许可证密钥。
在安装过程中获取用户输入有两种方法:
- 创建一个带有必填控件的窗体来获取输入(在安装期间无法将窗体作为模态弹出窗口打开)。 - 创建一个.wid文件以获取用户输入(这是推荐的方法)。
验证许可证密钥并在使用无效密钥时中止安装。
一旦在安装过程中获得了用户输入,您必须对其进行验证。您可以使用Installer Class完成此操作。 Install()方法示例
public override void Install(System.Collections.IDictionary stateSaver)
{
    //Invoke the base class method
    base.Install(stateSaver);

    if (!keyEnteredByUser.Equals(generatedKey))
    {
       //This would abort the installation
       throw new Exception("Invalid Key");
    }
}

1

我认为你应该看一下这个文章

在那篇文章中,他采用了与系统相同的方式生成唯一键。生成唯一键的方法如下。

public static string GetSystemInfo(string SoftwareName)
{
 if (UseProcessorID == true)

    SoftwareName += RunQuery("Processor", "ProcessorId");

if (UseBaseBoardProduct == true)

    SoftwareName += RunQuery("BaseBoard", "Product");

if (UseBaseBoardManufacturer == true)

    SoftwareName += RunQuery("BaseBoard", "Manufacturer");
// See more in source code

SoftwareName = RemoveUseLess(SoftwareName);

if (SoftwareName.Length < 25)

    return GetSystemInfo(SoftwareName);
return SoftwareName.Substring(0, 25).ToUpper();
}

private static string RunQuery(string TableName, string MethodName)
{
ManagementObjectSearcher MOS =
                 new ManagementObjectSearcher("Select * from Win32_" + TableName);
foreach (ManagementObject MO in MOS.Get())
{
    try
    {
        return MO[MethodName].ToString();
    }
    catch (Exception e)
    {
        System.Windows.Forms.MessageBox.Show(e.Message);
    }
}
return "";
}

以下是一种描述如何生成与唯一密钥匹配的密码代码的方法,

static public string MakePassword(string st, string Identifier)
{
if (Identifier.Length != 3)
    throw new ArgumentException("Identifier must be 3 character length");
int[] num = new int[3];
num[0] = Convert.ToInt32(Identifier[0].ToString(), 10);
num[1] = Convert.ToInt32(Identifier[1].ToString(), 10);
num[2] = Convert.ToInt32(Identifier[2].ToString(), 10);
st = Boring(st);
st = InverseByBase(st, num[0]);
st = InverseByBase(st, num[1]);
st = InverseByBase(st, num[2]);

StringBuilder SB = new StringBuilder();
foreach (char ch in st)
{
    SB.Append(ChangeChar(ch, num));
}
return SB.ToString();
} 

当用户输入正确的密码时,它将被存储在用户系统中,在下一次运行时不会再要求输入密码。
public static void WriteFile(string FilePath, string Data)
{
FileStream fout = new FileStream(FilePath, FileMode.OpenOrCreate,
  FileAccess.Write);
TripleDES tdes = new TripleDESCryptoServiceProvider();
CryptoStream cs = new CryptoStream(fout, tdes.CreateEncryptor(key, iv),
   CryptoStreamMode.Write);
byte[] d = Encoding.ASCII.GetBytes(Data);

cs.Write(d, 0, d.Length);
cs.WriteByte(0);

cs.Close();
fout.Close();
}

当你生成唯一密钥后,用户需要打电话给你并读取他的代码,然后根据该代码,您可以通过上述方法生成密码。
但是我的观点不同,这种方法与用户合作不好。让用户为获取密码而打电话浪费时间。最好尝试其他方法,让用户只需点击链接即可将项目设置为完整版。无论如何,以上方法应该可以解决您的问题。

@Ilya 不,那不是好的代码,也不接近于“正确的实现”,无论它是什么。这段代码本身、背后的思想以及其解释都有很多问题,我甚至不知道从哪里开始。例如,看看我在对OP的评论中链接的问题,其中讨论了更或多或少相等的代码实现。如果将此答案缩减为“您可以使用WMI获取某些硬件标识符,但它远非完美或独特”,那么它就是正确的并回答了一半的问题,但是由于包含了这段代码,它不太好。 - CodeCaster

0

我建议使用对称或非对称加密的方法 - 这是你必须寻找的方向,以提供基于机器的秘密密钥生成。在.NET中寻找它的模型

当然,如果你想让你的应用程序更加安全,你需要为其提供一个激活服务器,并附带客户端keyhashes数据库。


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