内容简介:如何保护软件版权,最常用的办法就是设计一套license验证框架。我们的常规需求如下:了解需求之后我们来对应设计License的结构:
如何保护软件版权,最常用的办法就是设计一套license验证框架。
我们的常规需求如下:
1.可以限制软件只能在一台机器上使用; 目前很多软件都是一机一码的销售,软件换一台机器则不能使用,想要几台机器使用就得购买几个license; 2.可以设置一个使用期限; 试用版软件一般有几十天的免费使用期,销售时也可以分为一年版、终生版等; 3.可以设置能使用的权限; 试用版软件对处理能力有限制,比如短信发送软件设置发送条数限制,抽奖软件设置总人数限制,打印软件试用版插一个软件广告等等;
了解需求之后我们来对应设计License的结构:
using System;
namespace LicenseDemo
{
[Serializable]
public class LicenseModel
{
//客户机器唯一识别码,由客户端生成
public string CustomMachineCode { get; set; }
//过期时间expire
public DateTime ExpireTime { get; set; }
//权限类型(如可分为 0: 15天试用版 1:1年版 2:终身版)
public int CustomRole { get; set; }
}
}
然后设计一下License分发和验证的流程:
todo:流程图
为了一机一码,license就要包含用户机器的唯一信息,我们可以通过获取机器硬件cpu、主板、bios、mac地址、显卡、声卡等的id来生成。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Security.Cryptography;
namespace LicenseDemo
{
public class HardwareInfo
{
private static string myMachineCode = "";
/// <summary>
/// Generates a 16 byte Unique Identification code of a computer
/// Example: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9
/// </summary>
/// <returns></returns>
public static string GetMachineCode()
{
if (string.IsNullOrEmpty(myMachineCode))
{
string omsg = " CPU >> " + CpuId() + " BIOS >> " +
BiosId() + " BASE >> " + BaseId();
// + " DISK >> " + DiskId() + " VIDEO >> " +
//VideoId() + " MAC >> " + MacId();
myMachineCode = MD5(omsg);
}
return myMachineCode;
}
/// <summary>
/// MD5哈希加密
/// </summary>
/// <param name="scr">原始string数据</param>
/// <returns>加密后的数据</returns>
private static string MD5(string scr)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] palindata = Encoding.Default.GetBytes(scr);//将要加密的字符串转换为字节数组
byte[] encryptdata = md5.ComputeHash(palindata);//将字符串加密后也转换为字符数组
return GetHexString(encryptdata);//将加密后的字节数组转换为加密字符串
}
/// <summary>
/// byte[]转换成十六进制
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
private static string GetHexString(byte[] bt)
{
string s = string.Empty;
for (int i = 0; i < bt.Length; i++)
{
byte b = bt[i];
int n, n1, n2;
n = (int)b;
n1 = n & 15;
n2 = (n >> 4) & 15;
if (n2 > 9)
s += ((char)(n2 - 10 + (int)'A')).ToString();
else
s += n2.ToString();
if (n1 > 9)
s += ((char)(n1 - 10 + (int)'A')).ToString();
else
s += n1.ToString();
if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
}
return s;
}
public static string CpuId()
{
//Uses first CPU identifier available in order of preference
//Don't get all identifiers, as it is very time consuming
string retVal = identifier("Win32_Processor", "UniqueId");
if (retVal == "") //If no UniqueID, use ProcessorID
{
retVal = identifier("Win32_Processor", "ProcessorId");
if (retVal == "") //If no ProcessorId, use Name
{
retVal = identifier("Win32_Processor", "Name");
if (retVal == "") //If no Name, use Manufacturer
{
retVal = identifier("Win32_Processor", "Manufacturer");
}
//Add clock speed for extra security
retVal += identifier("Win32_Processor", "MaxClockSpeed");
}
}
return retVal;
}
//BIOS Identifier
public static string BiosId()
{
return identifier("Win32_BIOS", "Manufacturer")
+ identifier("Win32_BIOS", "SMBIOSBIOSVersion")
+ identifier("Win32_BIOS", "IdentificationCode")
+ identifier("Win32_BIOS", "SerialNumber")
+ identifier("Win32_BIOS", "ReleaseDate")
+ identifier("Win32_BIOS", "Version");
}
//Main physical hard drive ID
public static string DiskId()
{
return identifier("Win32_DiskDrive", "Model")
+ identifier("Win32_DiskDrive", "Manufacturer")
+ identifier("Win32_DiskDrive", "Signature")
+ identifier("Win32_DiskDrive", "TotalHeads");
}
//Motherboard ID
public static string BaseId()
{
return identifier("Win32_BaseBoard", "Model")
+ identifier("Win32_BaseBoard", "Manufacturer")
+ identifier("Win32_BaseBoard", "Name")
+ identifier("Win32_BaseBoard", "SerialNumber");
}
//Primary video controller ID
public static string VideoId()
{
return identifier("Win32_VideoController", "DriverVersion")
+ identifier("Win32_VideoController", "Name");
}
//First enabled network card ID
public static string MacId()
{
return identifier("Win32_NetworkAdapterConfiguration",
"MACAddress", "IPEnabled");
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
{
string result = "";
ManagementClass mc =new ManagementClass(wmiClass);
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if (mo[wmiMustBeTrue].ToString() == "True")
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
}
return result;
}
//Return a hardware identifier
private static string identifier(string wmiClass, string wmiProperty)
{
string result = "";
ManagementClass mc =new ManagementClass(wmiClass);
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
//Only get the first one
if (result == "")
{
try
{
result = mo[wmiProperty].ToString();
break;
}
catch
{
}
}
}
return result;
}
}
}
View Code
上面的HardwareInfo类就是帮助生成机器唯一信息的。实际运用中,mac地址、声卡网卡等容易变动,可以不加到信息里面。
LicenseManage管理类的实现如下:
using System;
namespace LicenseDemo
{
public class LicenseManage
{
/// <summary>
/// 当前程序的license 业务层控制权限
/// </summary>
public static LicenseModel ApplicationLicense=null;
/// <summary>
/// 提取客户机器信息,返回编码
/// </summary>
/// <returns></returns>
public static string GetMachineCode()
{
return HardwareInfo.GetMachineCode();
}
private const string aeskey= "小y加;&tu@";
/// <summary>
/// 生成License文本给客户
/// </summary>
/// <param name="lic">LicenseModel对象,由客户提供机器码,并由商业提供期限和权限角色</param>
/// <returns></returns>
public static string CreateLicenseString(LicenseModel lic)
{
byte[] licByte = SerializeHelper.SerializeToBinary(lic);
return EncodeHelper.AES(Convert.ToBase64String(licByte), aeskey);
}
//验证license文本
public static bool VerifyLicense(string lic)
{
try
{
string strlic = EncodeHelper.AESDecrypt(lic, aeskey);
byte[] licbyte = Convert.FromBase64String(strlic);
LicenseModel lm = SerializeHelper.DeserializeWithBinary<LicenseModel>(licbyte);
LicenseManage.ApplicationLicense = lm;
//todo:验证
switch (lm.CustomRole)
{
case 0:
break;
}
//客户机器唯一识别码
return true;
}
catch
{
return false;
}
}
}
}
View Code
其中会用到类的序列化帮助工具:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace LicenseDemo
{
public class SerializeHelper
{
/// <summary>
/// 将对象序列化为二进制数据
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static byte[] SerializeToBinary(object obj)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, obj);
byte[] data = stream.ToArray();
stream.Close();
return data;
}
}
/// <summary>
/// 将二进制数据反序列化
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static object DeserializeWithBinary(byte[] data)
{
using (MemoryStream stream = new MemoryStream())
{
stream.Write(data, 0, data.Length);
stream.Position = 0;
BinaryFormatter bf = new BinaryFormatter();
object obj = bf.Deserialize(stream);
stream.Close();
return obj;
}
}
/// <summary>
/// 将二进制数据反序列化为指定类型对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
public static T DeserializeWithBinary<T>(byte[] data)
{
return (T)DeserializeWithBinary(data);
}
}
}
View Code
以及加解密工具:EncodeHelper 源码见我的另一篇文章:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 设计模式之软件设计七大原则
- 『互联网架构』软件架构-软件系统设计(一)
- 软件设计—UML类图详解
- 软件架构设计中的六大箴言
- 软件设计模式学习(十三)装饰模式
- 一文讲解软件架构设计核心逻辑(200724)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。