软件License设计

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

内容简介:如何保护软件版权,最常用的办法就是设计一套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-9

本书研究了无线是如何成为当代人类经验的主角的。从路由器、智能电话、电子书、城市到在线工作、服务协议、玩具以及国家等各个方面,人们已经感觉到了无线技术所引发的变革。本书作者援引一个世纪之前的哲学技术来分析当代最前沿的后网络时代的人类状况。基于威廉•詹姆斯的实用主义哲学相关的彻底经验主义,作者提出了把失序的无线网络世界与人们的感知匹配起来的新方式。一起来看看 《无线:网络文化中激进的经验主义》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具