翼度科技»论坛 编程开发 .net 查看内容

C# 软件Licence应用实例

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
我们在使用一些需要购买版权的软件产品时,或者我们做的商业软件需要进行售卖,为了收取费用,一般需要一个软件使用许可证,然后输入这个许可到软件里就能够使用软件。简单的是一串序列码或者一个许可证文件,复杂的是一个定制化插件包。于是有的小伙伴就开始好奇这个许可是怎么实现的,特别是在离线情况下它是怎么给软件授权,同时又能避免被破解的。

 
License应用场景

 
本文主要介绍的是许可证形式的授权。
 
1. 如何控制只在指定设备上使用

 
如果不控制指定设备,那么下发了许可证,只要把软件复制多份安装则可到处使用,不利于版权维护,每个设备都有唯一标识:mac地址,ip地址,主板序列号等,在许可证中指定唯一标识则只能指定设备使用。
 
2. 如何控制软件使用期限

 
为了版权可持续性收益,对软件使用设置期限,到期续费等,则需要在许可证中配置使用起止日期。
 
Licence实现方案

 
一、流程设计

 

  • 形式:许可证以文件形式下发,放在客户端电脑指定位置
  • 内容:以上控制内容以dom节点形式放在文件中
  • 流程:将控制项加密后写入license文件节点,部署到客户机器,客户机使用时再读取license文件内容与客户机实际参数进行匹配校验
 
二、文件防破解

 

  • 防止篡改:文件内容加密,使用AES加密,但是AES加密解密都是使用同一个key;使用非对称公私钥(本文使用的RSA)对内容加密解密,但是对内容长度有限制;综合方案,将AES的key(内部定义)用RSA加密,公钥放在加密工具中,内部持有,私钥放在解密工具中,引入软件产品解密使用。
  • 防止修改系统时间绕过许可证使用时间:许可证带上发布时间戳,并定时修改运行时间记录到文件,如果系统时间小于这个时间戳,就算大于许可证限制的起始时间也无法使用
  • 提高破解难度:懂技术的可以将代码反编译过来修改代码文件直接绕过校验,所以需要进行代码混淆,有测试过xjar的混淆效果比较好。
 
Licence验证流程图

 
关于Licence验证软件合法性流程图,如下所示:

 
核心源码

 
本实例主要讲解Licence的实际验证过程,分为三部分:

  • 测试客户端【LicenceTest】,主要用于模拟客户端验证Licence的过程。
  • 生成工具【LicenceTool】,主要用于根据客户生成的电脑文件,生成对应的Licence。
  • LicenceCommon,Licence公共通用类,主要实现电脑信息获取,非对称加密,文件保存等功能。
 
1. LicenceCommon

 
1.1 电脑信息获取

 
主要通过ManagementClass进行获取客户端电脑硬件相关配置信息,如下所示:
  1. using Microsoft.Win32;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Management;
  6. using System.Net.NetworkInformation;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace DemoLicence.Common
  10. {
  11.     public class ComputerHelper
  12.     {
  13.         public static Dictionary<string,string> GetComputerInfo()
  14.         {
  15.             var info = new Dictionary<string,string>();
  16.             string cpu = GetCPUInfo();
  17.             string baseBoard = GetBaseBoardInfo();
  18.             string bios = GetBIOSInfo();
  19.             string mac = GetMACInfo();
  20.             info.Add("cpu", cpu);
  21.             info.Add("baseBoard", baseBoard);
  22.             info.Add("bios", bios);
  23.             info.Add("mac", mac);
  24.             return info;
  25.         }
  26.         private static string GetCPUInfo()
  27.         {
  28.             string info = string.Empty;
  29.             info = GetHardWareInfo("Win32_Processor", "ProcessorId");
  30.             return info;
  31.         }
  32.         private static string GetBIOSInfo()
  33.         {
  34.             string info = string.Empty;
  35.             info = GetHardWareInfo("Win32_BIOS", "SerialNumber");
  36.             return info;
  37.         }
  38.         private static string GetBaseBoardInfo()
  39.         {
  40.             string info = string.Empty;
  41.             info = GetHardWareInfo("Win32_BaseBoard", "SerialNumber");
  42.             return info;
  43.         }
  44.         private static string GetMACInfo()
  45.         {
  46.             string info = string.Empty;
  47.             info = GetMacAddress();//GetHardWareInfo("Win32_NetworkAdapterConfiguration", "MACAddress");
  48.             return info;
  49.         }
  50.         private static string GetMacAddress()
  51.         {
  52.             var mac = "";
  53.             var mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
  54.             var moc = mc.GetInstances();
  55.             foreach (var o in moc)
  56.             {
  57.                 var mo = (ManagementObject)o;
  58.                 if (!(bool)mo["IPEnabled"]) continue;
  59.                 mac = mo["MacAddress"].ToString();
  60.                 break;
  61.             }
  62.             return mac;
  63.         }
  64.         private static string GetHardWareInfo(string typePath, string key)
  65.         {
  66.             try
  67.             {
  68.                 ManagementClass managementClass = new ManagementClass(typePath);
  69.                 ManagementObjectCollection mn = managementClass.GetInstances();
  70.                 PropertyDataCollection properties = managementClass.Properties;
  71.                 foreach (PropertyData property in properties)
  72.                 {
  73.                     if (property.Name == key)
  74.                     {
  75.                         foreach (ManagementObject m in mn)
  76.                         {
  77.                             return m.Properties[property.Name].Value.ToString();
  78.                         }
  79.                     }
  80.                 }
  81.             }
  82.             catch (Exception ex)
  83.             {
  84.                 //这里写异常的处理
  85.             }
  86.             return string.Empty;
  87.         }
  88.     }
  89. }
复制代码
 
1.3 RSA非对称加密

 
主要对客户端提供的电脑信息及有效期等内容,进行非对称加密,如下所示:
  1. public class RSAHelper
  2. {
  3.         private static string keyContainerName = "star";
  4.         private static string m_PriKey = string.Empty;
  5.         private static string m_PubKey = string.Empty;
  6.         public static string PriKey
  7.         {
  8.                 get
  9.                 {
  10.                         return m_PriKey;
  11.                 }
  12.                 set
  13.                 {
  14.                         m_PriKey = value;
  15.                 }
  16.         }
  17.         public static string PubKey
  18.         {
  19.                 get
  20.                 {
  21.                         return m_PubKey;
  22.                 }
  23.                 set
  24.                 {
  25.                         m_PubKey = value;
  26.                 }
  27.         }
  28.         public static string Encrypto(string source)
  29.         {
  30.                 if (string.IsNullOrEmpty(m_PubKey) && string.IsNullOrEmpty(m_PriKey))
  31.                 {
  32.                         generateKey();
  33.                 }
  34.                 return getEncryptoInfoByRSA(source);
  35.         }
  36.         public static string Decrypto(string dest)
  37.         {
  38.                 if (string.IsNullOrEmpty(m_PubKey) && string.IsNullOrEmpty(m_PriKey))
  39.                 {
  40.                         generateKey();
  41.                 }
  42.                 return getDecryptoInfoByRSA(dest);
  43.         }
  44.         public static void generateKey()
  45.         {
  46.                 CspParameters m_CspParameters;
  47.                 m_CspParameters = new CspParameters();
  48.                 m_CspParameters.KeyContainerName = keyContainerName;
  49.                 RSACryptoServiceProvider asym = new RSACryptoServiceProvider(m_CspParameters);
  50.                 m_PriKey = asym.ToXmlString(true);
  51.                 m_PubKey = asym.ToXmlString(false);
  52.                 asym.PersistKeyInCsp = false;
  53.                 asym.Clear();
  54.         }
  55.         private static string getEncryptoInfoByRSA(string source)
  56.         {
  57.                 byte[] plainByte = Encoding.ASCII.GetBytes(source);
  58.                 //初始化参数
  59.                 RSACryptoServiceProvider asym = new RSACryptoServiceProvider();
  60.                 asym.FromXmlString(m_PubKey);
  61.                 int keySize = asym.KeySize / 8;//非对称加密,每次的长度不能太长,否则会报异常
  62.                 int bufferSize = keySize - 11;
  63.                 if (plainByte.Length > bufferSize)
  64.                 {
  65.                         throw new Exception("非对称加密最多支持【" + bufferSize + "】字节,实际长度【" + plainByte.Length + "】字节。");
  66.                 }
  67.                 byte[] cryptoByte = asym.Encrypt(plainByte, false);
  68.                 return Convert.ToBase64String(cryptoByte);
  69.         }
  70.         private static string getDecryptoInfoByRSA(string dest)
  71.         {
  72.                 byte[] btDest = Convert.FromBase64String(dest);
  73.                 //初始化参数
  74.                 RSACryptoServiceProvider asym = new RSACryptoServiceProvider();
  75.                 asym.FromXmlString(m_PriKey);
  76.                 int keySize = asym.KeySize / 8;//非对称加密,每次的长度不能太长,否则会报异常
  77.                                                                            //int bufferSize = keySize - 11;
  78.                 if (btDest.Length > keySize)
  79.                 {
  80.                         throw new Exception("非对称解密最多支持【" + keySize + "】字节,实际长度【" + btDest.Length + "】字节。");
  81.                 }
  82.                 byte[] cryptoByte = asym.Decrypt(btDest, false);
  83.                 return Encoding.ASCII.GetString(cryptoByte);
  84.         }
  85. }
复制代码
 
1.3 生成文件

 
主要是加密后的信息,和解密秘钥等内容,保存到文件中,如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace DemoLicence.Common
  7. {
  8.     public class RegistFileHelper
  9.     {
  10.         public static string ComputerInfofile = "ComputerInfo.key";
  11.         public static string RegistInfofile = "Licence.key";
  12.         public static void WriteRegistFile(string info,string keyFile)
  13.         {
  14.             string tmp = string.IsNullOrEmpty(keyFile)?RegistInfofile:keyFile;
  15.             WriteFile(info, tmp);
  16.         }
  17.         public static void WriteComputerInfoFile(string info)
  18.         {
  19.             WriteFile(info, ComputerInfofile);
  20.         }
  21.         public static string ReadRegistFile(string keyFile)
  22.         {
  23.             string tmp = string.IsNullOrEmpty(keyFile) ? RegistInfofile : keyFile;
  24.             return ReadFile(tmp);
  25.         }
  26.         public static string ReadComputerInfoFile(string file)
  27.         {
  28.             string tmp = string.IsNullOrEmpty(file) ? ComputerInfofile : file;
  29.             return ReadFile(tmp);
  30.         }
  31.         private static void WriteFile(string info, string fileName)
  32.         {
  33.             try
  34.             {
  35.                 using (StreamWriter sw = new StreamWriter(fileName, false))
  36.                 {
  37.                     sw.Write(info);
  38.                     sw.Close();
  39.                 }
  40.             }
  41.             catch (Exception ex)
  42.             {
  43.             }
  44.         }
  45.         private static string ReadFile(string fileName)
  46.         {
  47.             string info = string.Empty;
  48.             try
  49.             {
  50.                 using (StreamReader sr = new StreamReader(fileName))
  51.                 {
  52.                     info = sr.ReadToEnd();
  53.                     sr.Close();
  54.                 }
  55.             }
  56.             catch (Exception ex)
  57.             {
  58.             }
  59.             return info;
  60.         }
  61.     }
  62. }
复制代码
以上这三部分,各个功能相互独立,通过LicenceHelper相互调用,如下所示:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.CompilerServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace DemoLicence.Common
  8. {
  9.     public class LicenceHelper
  10.     {
  11.         /// <summary>
  12.         /// 获取电脑信息,并生成文件
  13.         /// </summary>
  14.         public static string GetComputerInfoAndGenerateFile()
  15.         {
  16.             string computerKeyFile = string.Empty;
  17.             try
  18.             {
  19.                 var info = GetComputerInfo();
  20.                 if (info != null && info.Count > 0)
  21.                 {
  22.                     //获取到电脑信息
  23.                     var strInfo = new StringBuilder();
  24.                     foreach (var computer in info)
  25.                     {
  26.                         strInfo.AppendLine($"{computer.Key}={computer.Value}");
  27.                     }
  28.                     RegistFileHelper.WriteComputerInfoFile(strInfo.ToString());
  29.                     computerKeyFile = RegistFileHelper.ComputerInfofile;
  30.                 }
  31.             }catch(Exception ex)
  32.             {
  33.                 throw ex;
  34.             }
  35.             return computerKeyFile;
  36.         }
  37.         public static Dictionary<string,string> GetComputerInfo()
  38.         {
  39.             var info = ComputerHelper.GetComputerInfo();
  40.             return info;
  41.         }
  42.         public static bool CheckLicenceKeyIsExists()
  43.         {
  44.             var keyFile = RegistFileHelper.RegistInfofile;
  45.             if (File.Exists(keyFile))
  46.             {
  47.                 return true;
  48.             }
  49.             else
  50.             {
  51.                 return false;
  52.             }
  53.         }
  54.         public static string GetComputerInfo(string computerInfoFile)
  55.         {
  56.             return RegistFileHelper.ReadComputerInfoFile(computerInfoFile);
  57.         }
  58.         public static void GenerateLicenceKey(string info,string keyfile)
  59.         {
  60.             string encrypto = RSAHelper.Encrypto(info);
  61.             string priKey = RSAHelper.PriKey;//公钥加密,私钥解密
  62.             byte[] priKeyBytes = Encoding.ASCII.GetBytes(priKey);
  63.             string priKeyBase64=Convert.ToBase64String(priKeyBytes);
  64.             StringBuilder keyInfo= new StringBuilder();
  65.             keyInfo.AppendLine($"prikey={priKeyBase64}");
  66.             keyInfo.AppendLine($"encrypto={encrypto}");
  67.             RegistFileHelper.WriteRegistFile(keyInfo.ToString(), keyfile);
  68.         }
  69.         public static string ReadLicenceKey(string keyfile)
  70.         {
  71.             var keyInfo = RegistFileHelper.ReadRegistFile(keyfile);
  72.             if (keyInfo == null)
  73.             {
  74.                 return string.Empty;
  75.             }
  76.             string[] keyInfoArr = keyInfo.Split("\r\n");
  77.             var priKeyBase64 = keyInfoArr[0].Substring(keyInfoArr[0].IndexOf("=")+1);
  78.             var encrypto = keyInfoArr[1].Substring(keyInfoArr[1].IndexOf("=")+1);
  79.             var priKeyByte= Convert.FromBase64String(priKeyBase64);
  80.             var priKey = Encoding.ASCII.GetString(priKeyByte);
  81.             RSAHelper.PriKey= priKey;
  82.             var info = RSAHelper.Decrypto(encrypto);
  83.             return info;
  84.         }
  85.         public static string GetDefaultRegisterFileName()
  86.         {
  87.             return RegistFileHelper.RegistInfofile;
  88.         }
  89.         public static string GetDefaultComputerFileName()
  90.         {
  91.             return RegistFileHelper.ComputerInfofile;
  92.         }
  93.         
  94.         public static string GetPublicKey()
  95.         {
  96.             if (string.IsNullOrEmpty(RSAHelper.PubKey))
  97.             {
  98.                 RSAHelper.generateKey();
  99.             }
  100.             return RSAHelper.PubKey;
  101.         }
  102.         public static string GetPrivateKey()
  103.         {
  104.             if (string.IsNullOrEmpty(RSAHelper.PriKey))
  105.             {
  106.                 RSAHelper.generateKey();
  107.             }
  108.             return RSAHelper.PriKey;
  109.         }
  110.     }
  111. }
复制代码
 
2. 客户端LicenceTest

 
客户端验证Licence的有效性,当Licence有效时,正常使用软件,当Licence无效时,则不能正常使用软件。如下所示:
  1. using DemoLicence.Common;
  2. namespace LicenceTest
  3. {
  4.     public partial class MainForm : Form
  5.     {
  6.         public MainForm()
  7.         {
  8.             InitializeComponent();
  9.         }
  10.         private void MainForm_Load(object sender, EventArgs e)
  11.         {
  12.             try
  13.             {
  14.                 string info = string.Empty;
  15.                 string msg = string.Empty;
  16.                 //初始化加载
  17.                 if (LicenceHelper.CheckLicenceKeyIsExists())
  18.                 {
  19.                     string keyFile = LicenceHelper.GetDefaultRegisterFileName();
  20.                     info = LicenceHelper.ReadLicenceKey(keyFile);
  21.                 }
  22.                 else
  23.                 {
  24.                     var dialogResult = MessageBox.Show("没有找到默认首选文件,是否手动选择授权文件?", "询问", MessageBoxButtons.YesNo);
  25.                     if (dialogResult == DialogResult.Yes)
  26.                     {
  27.                         OpenFileDialog openFileDialog = new OpenFileDialog();
  28.                         openFileDialog.Title = "请选择授权文件";
  29.                         openFileDialog.FileName = LicenceHelper.GetDefaultRegisterFileName();
  30.                         if (openFileDialog.ShowDialog() == DialogResult.OK)
  31.                         {
  32.                             var keyFile = openFileDialog.FileName;
  33.                             info = LicenceHelper.ReadLicenceKey(keyFile);
  34.                             //验证成功后,将手动选择的文件复制到程序根目录,且修改为默认名称
  35.                             File.Copy(keyFile, LicenceHelper.GetDefaultRegisterFileName());
  36.                         }
  37.                         else
  38.                         {
  39.                             string computerFile = LicenceHelper.GetComputerInfoAndGenerateFile();
  40.                             if (!string.IsNullOrEmpty(computerFile))
  41.                             {
  42.                                 msg = $"您还没有被授权,请将程序根目录下的{computerFile}文件,发送到管理员,获取Licence.";
  43.                             }
  44.                         }
  45.                     }
  46.                     else
  47.                     {
  48.                         string computerFile = LicenceHelper.GetComputerInfoAndGenerateFile();
  49.                         if (!string.IsNullOrEmpty(computerFile))
  50.                         {
  51.                             msg = $"您还没有被授权,请将程序根目录下的{computerFile}文件,发送到管理员,获取Licence.";
  52.                         }
  53.                     }
  54.                 }
  55.                 if (!string.IsNullOrEmpty(info) && string.IsNullOrEmpty(msg))
  56.                 {
  57.                     string[] infos = info.Split("\r\n");
  58.                     if (infos.Length > 0)
  59.                     {
  60.                         var dicInfo = new Dictionary<string, string>();
  61.                         foreach (var info2 in infos)
  62.                         {
  63.                             if (string.IsNullOrEmpty(info2))
  64.                             {
  65.                                 continue;
  66.                             }
  67.                             var info2Arr = info2.Split("=");
  68.                             dicInfo.Add(info2Arr[0], info2Arr[1]);
  69.                         }
  70.                         if (dicInfo.Count > 0)
  71.                         {
  72.                             string localMacAddress = string.Empty;
  73.                             var computerInfo = LicenceHelper.GetComputerInfo();
  74.                             if (computerInfo != null)
  75.                             {
  76.                                 localMacAddress = computerInfo["mac"];
  77.                             }
  78.                             //比较本地信息和Licence中的信息是否一致
  79.                             if (localMacAddress == dicInfo["mac"])
  80.                             {
  81.                                 var endTime = DateTime.Parse(dicInfo["endTime"]);
  82.                                 if (DateTime.Now < endTime)
  83.                                 {
  84.                                     //在有效期内,可以使用
  85.                                 }
  86.                                 else
  87.                                 {
  88.                                     msg = $"软件授权使用时间范围:[{endTime}之前],已过期";
  89.                                 }
  90.                             }
  91.                             else
  92.                             {
  93.                                 msg = "软件Licence不匹配";
  94.                             }
  95.                         }
  96.                         else
  97.                         {
  98.                             msg = $"软件Licence非法.";
  99.                         }
  100.                     }
  101.                     else
  102.                     {
  103.                         msg = $"软件Licence非法.";
  104.                     }
  105.                 }
  106.                 if (!string.IsNullOrEmpty(msg))
  107.                 {
  108.                     MessageBox.Show(msg);
  109.                     foreach (var control in this.Controls)
  110.                     {
  111.                         (control as Control).Enabled = false;
  112.                     }
  113.                     return;
  114.                 }
  115.             }
  116.             catch (Exception ex)
  117.             {
  118.                 string error = $"程序异常,请联系管理人员:{ex.Message}\r\n{ex.StackTrace}";
  119.                 MessageBox.Show(error);
  120.                 foreach (var control in this.Controls)
  121.                 {
  122.                     (control as Control).Enabled = false;
  123.                 }
  124.             }
  125.         }
  126.     }
  127. }
复制代码
 
3. Licence生成工具

 
LicenceTool主要根据客户端提供的电脑信息,生成对应的Licence,然后再发送给客户端,以此达到客户端电脑的授权使用软件的目的。如下所示:
  1. using DemoLicence.Common;
  2. using System.Text;
  3. namespace LicenceTool
  4. {
  5.     public partial class MainForm : Form
  6.     {
  7.         public MainForm()
  8.         {
  9.             InitializeComponent();
  10.         }
  11.         private void MainForm_Load(object sender, EventArgs e)
  12.         {
  13.             this.txtPublicKey.Text=LicenceHelper.GetPublicKey();
  14.             this.txtPrivateKey.Text=LicenceHelper.GetPrivateKey();
  15.         }
  16.         private void btnBrowser_Click(object sender, EventArgs e)
  17.         {
  18.             OpenFileDialog ofd = new OpenFileDialog();
  19.             ofd.Filter = "电脑信息文件|*.key";
  20.             ofd.Multiselect = false;
  21.             ofd.Title = "请选择电脑信息文件";
  22.             ofd.FileName=LicenceHelper.GetDefaultComputerFileName();
  23.             if (ofd.ShowDialog() == DialogResult.OK)
  24.             {
  25.                 this.txtSourceFile.Text = ofd.FileName;
  26.             }
  27.         }
  28.         private void btnGenerate_Click(object sender, EventArgs e)
  29.         {
  30.             try
  31.             {
  32.                 if (string.IsNullOrEmpty(this.txtSourceFile.Text))
  33.                 {
  34.                     MessageBox.Show("请先选择电脑信息文件");
  35.                     return;
  36.                 }
  37.                 if (File.Exists(this.txtSourceFile.Text))
  38.                 {
  39.                     //读取电脑文件
  40.                     var info = LicenceHelper.GetComputerInfo(this.txtSourceFile.Text);
  41.                     int days = GetLicenceDays();
  42.                     var keyInfos = new StringBuilder(info);
  43.                     var beginTime = DateTime.Now;
  44.                     var endTime = DateTime.Now.AddDays(days);
  45.                     //keyInfos.AppendLine($"beginTime={beginTime.ToString("yyyy-MM-dd HH:mm:ss")}");
  46.                     keyInfos.AppendLine($"endTime={endTime.ToString("yyyy-MM-dd HH:mm:ss")}");
  47.                     //
  48.                     info = keyInfos.ToString();
  49.                     SaveFileDialog saveFileDialog = new SaveFileDialog();
  50.                     saveFileDialog.Title = "保存生成的Licence文件";
  51.                     saveFileDialog.FileName = LicenceHelper.GetDefaultRegisterFileName();
  52.                     if (saveFileDialog.ShowDialog() == DialogResult.OK)
  53.                     {
  54.                         LicenceHelper.GenerateLicenceKey(info, saveFileDialog.FileName);
  55.                         MessageBox.Show("生成成功");
  56.                     }
  57.                 }
  58.                 else
  59.                 {
  60.                     MessageBox.Show("电脑信息文件不存在!");
  61.                     return;
  62.                 }
  63.             }catch(Exception ex)
  64.             {
  65.                 string error = $"生成出错:{ex.Message}\r\n{ex.StackTrace}";
  66.                 MessageBox.Show(error);
  67.             }
  68.         }
  69.         /// <summary>
  70.         /// 获取有效期天数
  71.         /// </summary>
  72.         /// <returns></returns>
  73.         private int GetLicenceDays()
  74.         {
  75.             int days = 1;
  76.             RadioButton[] rbtns = new RadioButton[] { this.rbtSeven, this.rbtnTen, this.rbtnFifteen, this.rbtnThirty, this.rbtnSixty, this.rbtnSixMonth, this.rbtnNinety, this.rbtnSixMonth, this.rbtnForver };
  77.             foreach (RadioButton rb in rbtns)
  78.             {
  79.                 if (rb.Checked)
  80.                 {
  81.                     if (!int.TryParse(rb.Tag.ToString(), out days))
  82.                     {
  83.                         days = 0;
  84.                     }
  85.                     break;
  86.                 }
  87.             }
  88.             days = days == -1 ? 9999 : days;//永久要转换一下
  89.             return days;
  90.         }
  91.     }
  92. }
复制代码
 
测试验证

 
启动软件时会进行校验,在没有Licence时,会有信息提示,且无法使用软件,如下所示:

Lincence生成工具
根据客户提供的电脑信息文件,生成对应的Licence,如下所示:

生成Licence放在客户端默认目录下,即可正常使用软件,如下所示:

注意:非对称加密每次生成的秘钥都是不同的,所以需要将解密秘钥一起保存到生成的Licence文件中,否则秘钥不同,则无法解密。
生成的电脑信息文件ComputerInfo.key示例如下所示:

生成的Licence.key文件内容,如下所示:

 
源码下载

 
源码下载可以通过以下3种方式,
 
1. 公众号关键词回复

 
关注个人公众号,回复关键字【Licence】获取源码,如下所示:

 
2. 通过gitee(码云)下载

 
本示例中相关源码,已上传至gitee(码云),链接如下:

 
3. 通过CSDN进行下载

 
通过CSDN上的资源进行付费下载,不贵不贵,也就一顿早餐的钱。
https://download.csdn.net/download/fengershishe/88294433?spm=1001.2014.3001.5501

以上就是软件Licence应用实例的全部内容,希望可以抛砖引玉,一起学习,共同进步。学习编程,从关注【老码识途】开始!!!

来源:https://www.cnblogs.com/hsiang/archive/2023/09/03/17675115.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具