20
4月
2020

C#双重密钥激活软件和试用限制

当你拿到客户的软件开发需求,经过了若干个熬夜的日子终于调试好软件后,你是否想直接发送安装包给客户尽快交差?运气好你可能收获一波领导或客户的彩虹屁,但大部分时候你只会被客户各种挑剔甚至不付尾款!现实就是这样残酷,今天我将教大家使用明码和暗码双重密钥给软件激活和设置试用期限,避免被客户白P!

逻辑思路很简单,密钥由电脑的CPU信息+当前日期组成并经过DES加密,一方面将密钥写入注册表中作为明码,另一方面将密钥写入指定盘创建的隐藏文件中,软件运行时需要同时读取明码和暗码并进行比较,一致则验证通过,不一致则退出程序,安装时对暗码文件不替换,这样可以防止客户重装软件。

1.DES加解密类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace softwareTrial
{
    class DES
    {
        /// <summary>  
        /// C# DES解密方法  
        /// </summary>  
        /// <param name="encryptedValue">待解密的字符串</param>  
        /// <param name="key">密钥</param>  
        /// <param name="iv">向量</param>  
        /// <returns>解密后的字符串</returns>  
        public static string DESDecrypt(string encryptedValue, string key, string iv)
        {
            using (DESCryptoServiceProvider sa =
                new DESCryptoServiceProvider
                { Key = Encoding.UTF8.GetBytes(key), IV = Encoding.UTF8.GetBytes(iv) })
            {
                using (ICryptoTransform ct = sa.CreateDecryptor())
                {
                    byte[] byt = Convert.FromBase64String(encryptedValue);

                    using (var ms = new MemoryStream())
                    {
                        using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
                        {
                            cs.Write(byt, 0, byt.Length);
                            cs.FlushFinalBlock();
                        }
                        return Encoding.UTF8.GetString(ms.ToArray());
                    }
                }
            }
        }


        /// <summary>  
        /// C# DES加密方法  
        /// </summary>  
        /// <param name="encryptedValue">要加密的字符串</param>  
        /// <param name="key">密钥</param>  
        /// <param name="iv">向量</param>  
        /// <returns>加密后的字符串</returns>  
        public static string DESEncrypt(string originalValue, string key, string iv)
        {
            using (DESCryptoServiceProvider sa
                = new DESCryptoServiceProvider { Key = Encoding.UTF8.GetBytes(key), IV = Encoding.UTF8.GetBytes(iv) })
            {
                using (ICryptoTransform ct = sa.CreateEncryptor())
                {
                    byte[] by = Encoding.UTF8.GetBytes(originalValue);
                    using (var ms = new MemoryStream())
                    {
                        using (var cs = new CryptoStream(ms, ct,
                                                         CryptoStreamMode.Write))
                        {
                            cs.Write(by, 0, by.Length);
                            cs.FlushFinalBlock();
                        }
                        return Convert.ToBase64String(ms.ToArray());
                    }
                }
            }
        }
    }
}

2.Time辅助类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Microsoft.Win32;
using System.Management;

namespace softwareTrial
{
    class Time
    {     
        /// <summary>
        /// 获取电脑CPU信息的方法
        /// </summary>
        /// <returns></returns>
        public static string GetCpuId()
        {
            ManagementClass mc = new ManagementClass("Win32_Processor");
            ManagementObjectCollection moc = mc.GetInstances();

            string strCpuID = null;
            foreach (ManagementObject mo in moc)
            {
                strCpuID = mo.Properties["ProcessorId"].Value.ToString();
                break;
            }
            return strCpuID;
        }

        /// <summary>
        /// 获取系统当前时间的方法
        /// </summary>
        /// <returns></returns>
        public static string GetNowDate()
        {
            string NowDate = DateTime.Now.ToString("yyyyMMdd"); 
            return NowDate;
        }

        /// <summary>
        /// 生成序列号的方法
        /// </summary>
        /// <returns></returns>
        public static string CreatSerialNumber()
        {
            string SerialNumber = GetCpuId() + "-" + GetNowDate();
            return SerialNumber;
        }
       

        /// <summary>
        /// 写入注册表的方法
        /// </summary>
        /// <param name="Section"></param>
        /// <param name="Key"></param>
        /// <param name="Setting"></param>
        public static void WriteSetting(string Section, string Key, string Setting)  // name = key  value=setting  Section= path
        {
            string text1 = Section;
            RegistryKey key1 = Registry.CurrentUser.CreateSubKey("Software\\TestItem"); // .LocalMachine.CreateSubKey("Software\\mytest");
            if (key1 == null)
            {
                return;
            }
            try
            {
                key1.SetValue(Key, Setting);
            }
            catch (Exception exception)
            {
                return;
            }
            finally
            {
                key1.Close();
            }

        }

        /// <summary>
        /// 读取注册表的方法
        /// </summary>
        /// <param name="Section"></param>
        /// <param name="Key"></param>
        /// <param name="Default"></param>
        /// <returns></returns>
        public static string ReadSetting(string Section, string Key, string Default)
        {
            if (Default == null)
            {
                Default = "-1";
            }
            string text2 = Section;
            RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Software\\TestItem");
            if (key1 != null)
            {
                object obj1 = key1.GetValue(Key, Default);
                key1.Close();
                if (obj1 != null)
                {
                    if (!(obj1 is string))
                    {
                        return "-1";
                    }
                    string obj2 = obj1.ToString();
                    obj2 = DES.DESDecrypt(obj2, "12345678", "87654321");
                    return obj2;
                }
                return "-1";
            }
            return Default;
        }
    }
}

3.创建明码

private void Button1_Click(object sender, EventArgs e)
        {      
            RegistryWrite();
            MessageBox.Show("已创建明码!");
        }

4.创建暗码

private void Button2_Click(object sender, EventArgs e)
        {
            triaDate = Time.CreatSerialNumber();
            createHiddentFile(DES.DESEncrypt(triaDate, "12345678", "87654321"));
            MessageBox.Show("已创建暗码!");
        }

5.密钥对比

private void Button3_Click(object sender, EventArgs e)
        {
            //注册表密钥
            RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Software\\TestItem");
            if (key1 != null)
            {

                object obj1 = key1.GetValue("SerialNumber");
                string aa = obj1.ToString();
                string bb = DES.DESDecrypt(aa, "12345678", "87654321");
                registryKey = bb.Substring(bb.Length - 8);

                /* 比较时间 */
                string NowDate = Time.GetNowDate();
                timeGap = Convert.ToInt32(NowDate) - Convert.ToInt32(registryKey);
            }
            else
            {
                ;
            }

            //TXT密钥
            readHiddentFile();

            //注册表TestItem项是否存在
            bool itemExit = IsRegeditItemExist();


            if (registryKey == textKey && timeGap < Convert.ToInt32(textBox1.Text))
            {
                MessageBox.Show("密钥验证一致!");
                label2.Visible = true;
                label2.Text = "欢迎访问大博客(https://www.daboke.com)探索更多编程实战案例!";
            }
            else if (registryKey == textKey && timeGap > Convert.ToInt32(textBox1.Text))
            {
                MessageBox.Show("软件试用到期!");
                this.Close();
            }
            else if (itemExit == false)
            {
                MessageBox.Show("软件尚未注册,不可使用!");
            }
            else if (itemExit == true && registryKey != textKey)
            {
                MessageBox.Show("密钥验证不一致,请联系管理员!");
                this.Close();
            }
            else
            {
                MessageBox.Show("软件运行出错,请联系管理员!");
                this.Close();
            }

        }

6.软件说明

interface

图1-软件界面

1)注册日期TextBOX中写入试用天数。

2)点击”创建明码”按钮,注册表HKEY_CURRENT_USER\Software\TestItem新建”SerialNumber”项,写入密钥。

3)点击”创建暗码”按钮,D盘新建testtxt.txt隐藏文件,写入密钥。

4)点击”密钥对比”按钮,自动反馈结果。

本案例通过三个简单的按钮演示了设置软件试用期限的方法, 实际使用时你需要将”密钥对比”内的代码和程序的主函数绑定,即如果验证不一致或试用到期则主函数功能不可用,从而实现软件试用限制的功能。


代码全文:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using System.IO;

namespace softwareTrial
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            label2.Visible = false;
        }

        string triaDate;//注册表中的注册日期
        string triaDateInFile;//TXT中的注册日期
        string registryKey = "";//注册表密钥
        string textKey = "";//TXT密钥
        int timeGap = 0;//时间间隔


        /// <summary>
        /// 判断注册表项目是否存在的方法
        /// </summary>
        /// <returns></returns>
        private bool IsRegeditItemExist()
        {
            string[] subkeyNames;
            RegistryKey hkml = Registry.CurrentUser;
            RegistryKey software = hkml.OpenSubKey("SOFTWARE");
            //RegistryKey software = hkml.OpenSubKey(SOFTWARE, true);
            subkeyNames = software.GetSubKeyNames();
            //取得该项下所有子项的名称的序列,并传递给预定的数组中  
            foreach (string keyName in subkeyNames) //遍历整个数组
            {
                if (keyName == "TestItem") //判断子项的名称
                {
                    hkml.Close();
                    return true;
                }
            }
            hkml.Close();
            return false;
        }


        /// <summary>
        /// 注册表写入密钥的方法
        /// </summary>
        private void RegistryWrite()
        {
            bool isExit = IsRegeditItemExist();
            if (isExit != true)
            {
                string sn, sm;
                sn = Time.CreatSerialNumber();
                sm = DES.DESEncrypt(sn, "12345678", "87654321");
                Time.WriteSetting("", "SerialNumber", sm);
            }
        }

        /// <summary>
        /// 创建隐藏文件的方法
        /// </summary>
        /// <param name="key"></param>
        public void createHiddentFile(string key)
        {
            //判断是否已经有了这个文件
            if (!System.IO.File.Exists("d:\\testtxt.txt"))
            {
                //没有则创建这个文件
                FileStream fs1 = new FileStream("d:\\testtxt.txt", FileMode.Create, FileAccess.Write);//创建写入文件                
                //设置文件属性为隐藏
                System.IO.File.SetAttributes(@"d:\\testtxt.txt", FileAttributes.Hidden);
                StreamWriter sw = new StreamWriter(fs1);
                sw.WriteLine(key.Trim());//开始写入值
                sw.Close();
                fs1.Close();
            }
            else
            {
                ;
            }

        }

        /// <summary>
        /// 读取隐藏文件的方法
        /// </summary>
        public void readHiddentFile()
        {
            string[] content = System.IO.File.ReadAllLines("d:\\testtxt.txt", Encoding.Default);
            if (System.IO.File.Exists("d:\\testtxt.txt"))
            {
                if (content != null)
                {
                    //txtExit = true;
                    for (int i = 0; i < content.Length; i++)
                    {
                        triaDateInFile = content[i];
                        triaDateInFile = DES.DESDecrypt(triaDateInFile, "12345678", "87654321");
                        textKey = triaDateInFile.Substring(triaDateInFile.Length - 8);
                    }
                }
                else
                {
                    ;
                }
            }
            else
            {
                ;
            }

        }


        private void Button1_Click(object sender, EventArgs e)
        {
            RegistryWrite();
            MessageBox.Show("已创建明码!");
        }

        private void Button2_Click(object sender, EventArgs e)
        {
            triaDate = Time.CreatSerialNumber();
            createHiddentFile(DES.DESEncrypt(triaDate, "12345678", "87654321"));
            MessageBox.Show("已创建暗码!");
        }

        private void Button3_Click(object sender, EventArgs e)
        {
            //注册表密钥
            RegistryKey key1 = Registry.CurrentUser.OpenSubKey("Software\\TestItem");
            if (key1 != null)
            {

                object obj1 = key1.GetValue("SerialNumber");
                string aa = obj1.ToString();
                string bb = DES.DESDecrypt(aa, "12345678", "87654321");
                registryKey = bb.Substring(bb.Length - 8);

                /* 比较时间 */
                string NowDate = Time.GetNowDate();
                timeGap = Convert.ToInt32(NowDate) - Convert.ToInt32(registryKey);
            }
            else
            {
                ;
            }

            //TXT密钥
            readHiddentFile();

            //注册表TestItem项是否存在
            bool itemExit = IsRegeditItemExist();


            if (registryKey == textKey && timeGap < Convert.ToInt32(textBox1.Text))
            {
                MessageBox.Show("密钥验证一致!");
                label2.Visible = true;
                label2.Text = "欢迎访问大博客(https://www.daboke.com)探索更多编程实战案例!";
            }
            else if (registryKey == textKey && timeGap > Convert.ToInt32(textBox1.Text))
            {
                MessageBox.Show("软件试用到期!");
                this.Close();
            }
            else if (itemExit == false)
            {
                MessageBox.Show("软件尚未注册,不可使用!");
            }
            else if (itemExit == true && registryKey != textKey)
            {
                MessageBox.Show("密钥验证不一致,请联系管理员!");
                this.Close();
            }
            else
            {
                MessageBox.Show("软件运行出错,请联系管理员!");
                this.Close();
            }

        }

        private void Button6_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://www.daboke.com");//欢迎访问大博客,探索更多编程实战案例!
        }

        private void Button7_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("https://www.daboke.com/program/activationandtrial");//原文链接!
        }
    }
}

代码链接:

softwareTrial

原文链接:

https://www.daboke.com/program/activationandtrial.html

You may also like...

2 Responses

  1. 陈龙兴说道:

    你好,我正需要一个这样的验证,但是我测试了您这个验证,到期以后修改一下时间为拿到文件的日期有可以正常使用了,这个有办法对比网站时间吗?

    • 威廉说道:

      是的,文章的这个方法是针对电脑单机的,您说的这种方式需要从服务器读取时间做对比。

发表评论

邮箱地址不会被公开。

微信 OR 支付宝 扫描二维码
为本文作者 打个赏
pay_weixin pay_weixin
最喜欢你一言不合就打赏的样子了^_^