软件License设计

栏目: 编程工具 · 发布时间: 4年前

内容简介:如何保护软件版权,最常用的办法就是设计一套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    源码见我的另一篇文章:

常见加密算法简析


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

四维人类

四维人类

(英)劳伦斯·斯科特 / 祝锦杰 / 浙江教育出版社 / 2018-10 / 79.90元

数字技术如何重新定义 我们的思维方式与生存方式?一起来看看 《四维人类》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具