在工业软件或其他领域中,经常会对软件进行授权,软件需要付费进行有期限的使用。以下是我用Qt设计的设置软件使用期限的两种方案。

主体思想:

1.软件需要绑定机器,让用户无法通过复制在另一台机器上运行。

2.由厂家提供激活码供用户激活,每个激活码只对应指定的机器有效,且激活码需包含使用期限。为保证激活码不能重复使用,激活码需包含当天的日期信息,令激活码仅当天有效,软件过期或许可证丢失后无法使用之前激活码进行激活。

3.由于2的限制,因此需要在每台机器上产生机器码,供厂家用来生成激活码。

4.需有校验功能,校验激活码是否有效,校验是否过期。为了避免用户修改系统时间来延长使用期限,需要验证许可证中最后使用日期是否大于当前日期,若是,则说明用户修改了系统时间,校验不通过,此时可以在代码中删除许可证,或直接退出软件。

5.需要保存许可证或注册表。许可证和注册表信息存储的是当前激活的密钥和最后使用日期、有效期限。并在每次开启和关闭软件时对许可证内的最后使用日期进行更新。

一、获取机器码

要绑定机器,就要获取到机器的唯一标识,网卡的MAC地址是个不错的选择,因此可以拿MAC地址当做机器码。

QString getMachineCode(){QString text;//获取非00-00-00-00-00-00的mac地址QRegExp regmac("00.00.00.00.00.00");foreach(QNetworkInterface interface,QNetworkInterface::allInterfaces()){text = interface.hardwareAddress();if(text.indexOf(regmac)>=0)continue;elsebreak;}QString machineCode;for(int i=0;i<6;i++){machineCode.append(text.mid(0,2));text.remove(0,3);}return machineCode;
}

二、生成带使用期限的激活码

激活码可以自己编写一些算法,通过各种计算、移位、换位等操作来生成。下面是我的示例:

QString newFunction(QString mc, int day)//mc为机器码,day为使用期限
{QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}
//激活码中日期信息QDate date = QDate::currentDate();int y=date.year()-2000;int m=date.month();int d=date.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);qDebug()<<dts;int dt = dts.toInt(nullptr,2);QString dthex = QString::number(dt,16);QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);QStringList binlst;binlst.append(hexToBin(copycode.mid(0,2)));binlst.append(hexToBin(copycode.mid(2,2)));binlst.append(hexToBin(copycode.mid(4,2)));binlst.append(hexToBin(copycode.mid(6,2)));binlst.append(hexToBin(copycode.mid(8,2)));binlst.append(hexToBin(copycode.mid(10,2)));int jy = 0;for(int i=7;i>=0;i--){int nums=0;for(int j=0;j<6;j++){if(binlst.at(j).at(i)=='1')nums++;}if(nums%2==1)jy += 1<<i;}qDebug()<<jy;jy += day;int local = day%6;copycode.insert(local*2,tenToHexL(jy));copycode.append(dthex);qDebug()<<copycode;return copycode;
}

三、校验激活码

校验的过程其实就是生成激活码(不带期限),与带期限的激活码进行比对和运算,判断其是否有效,若有效则计算使用期限。

int Widget::getValidity(QString code)
{QDate date = QDate::currentDate();int y=date.year()-2000;int m=date.month();int d=date.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = dts.toInt(nullptr,2);QString dthex = QString::number(dt,16);if(dthex!=code.mid(16,4)){//激活码内日期与当前日期不符,激活码过期qDebug()<<"code over time!";return 0;}code.remove(16,4);QString mc = getMachineCode();QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);QStringList binlst;binlst.append(hexToBin(copycode.mid(0,2)));binlst.append(hexToBin(copycode.mid(2,2)));binlst.append(hexToBin(copycode.mid(4,2)));binlst.append(hexToBin(copycode.mid(6,2)));binlst.append(hexToBin(copycode.mid(8,2)));binlst.append(hexToBin(copycode.mid(10,2)));int jy = 0;for(int i=7;i>=0;i--){int nums=0;for(int j=0;j<6;j++){if(binlst.at(j).at(i)=='1')nums++;}if(nums%2==1)jy += 1<<i;}int validity=0;for(int i=0;i<12;i+=2){if(copycode.mid(i,2)!=code.mid(i,2)){validity = code.mid(i,4).toInt(nullptr,16)-jy;code.remove(i,4);break;}}if(copycode==code){//激活码有效,生成许可证writeLicense(copycode,dthex,validity);return validity;}elsereturn 0;
}

四、生成许可证

为了后续校验方便,许可证内的激活码可以省略最后几个步骤。许可证内容由三部分组成:激活码、最后使用日期、软件有效期。

void writeLicense(QString code,QString dthex,int days)
{QDate yxq = QDate::currentDate().addDays(days);int y=yxq.year()-2000;int m=yxq.month();int d=yxq.day();QString dts = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = dts.toInt(nullptr,2);QString yxqhex = QString::number(dt,16);QFile file("license.dat");file.open(QIODevice::WriteOnly);QDataStream ds(&file);QByteArray ba;ba.resize(10);for(int i=0;i<6;i++){ba[i]=uchar(code.mid(i*2,2).toUInt(nullptr,16));}ba[6]=uchar(dthex.mid(0,2).toUInt(nullptr,16));ba[7]=uchar(dthex.mid(2,2).toUInt(nullptr,16));ba[8]=uchar(yxqhex.mid(0,2).toUInt(nullptr,16));ba[9]=uchar(yxqhex.mid(2,2).toUInt(nullptr,16));ds<<(QByteArray)ba;file.flush();file.close();
}

五、软件每次启动时校验许可证

void Widget::checkLicense()
{QFile file("license.dat");file.open(QIODevice::ReadOnly);QDataStream ds(&file);QByteArray ba;ds>>ba;QString code = ba.toHex();QString shortcode = code.mid(0,12);QString mc = getMachineCode();QString newcode;for(int i=0;i<6;i++){int index=mc.mid(i*2,2).toUInt(nullptr,16);newcode.append(QString::number(pwd[index],16));}QString copycode = newcode;copycode.replace(0,1,newcode[1]);copycode.replace(1,1,newcode[0]);copycode.replace(2,1,newcode[4]);copycode.replace(4,1,newcode[2]);copycode.replace(7,1,newcode[10]);copycode.replace(10,1,newcode[7]);if(shortcode!=copycode){//激活码错误qDebug()<<"校验不通过";return;}QDate lastDate;QString dts = code.mid(12,4);int idt = dts.toInt(nullptr,16);int y = idt>>9;int m = (idt>>5) & ((1<<4)-1);int d = idt & ((1<<5)-1);lastDate.setDate(y+2000,m,d);if(lastDate.daysTo(QDate::currentDate())<0){//用户修改了系统时间qDebug()<<"时间非法";return;}QDate today = QDate::currentDate();y=today.year()-2000;m=today.month();d=today.day();QString s_today = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = s_today.toInt(nullptr,2);QString s_yxq = code.mid(16,4);if(s_yxq.toInt(nullptr,16)<dt){//许可证已过期qDebug()<<"已过期";return;}
}

六、更新许可证

为防止用户篡改系统时间以达到延长使用期限的目的,许可证中加入了最后使用日期进行校验。在每次软件启动校验成功后、软件关闭时,更新许可证中的最后使用日期。

void updateLicense()
{QFile file("license.dat");file.open(QIODevice::ReadWrite);QDataStream ds(&file);QByteArray ba;ds>>ba;QDate today = QDate::currentDate();int y=today.year()-2000;int m=today.month();int d=today.day();QString s_today = intToBin(y,7)+intToBin(m,4)+intToBin(d,5);int dt = s_today.toInt(nullptr,2);QString hex = QString::number(dt,16);ba[6]=uchar(hex.mid(0,2).toUInt(nullptr,16));ba[7]=uchar(hex.mid(2,2).toUInt(nullptr,16));file.resize(0);file.seek(0);ds<<ba;file.flush();file.close();
}

以上内容为本地生成许可证的方式,也可以用写注册表的方式来代替,主体思想不变。

想要完成代码的朋友可以私信作者获取。

请大家多多关注与支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93698.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93698.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/93698.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaEE】多线程(线程安全问题)

有些代码在单个线程环境下执行正确&#xff0c;如果同样的代码在多个线程下同时执行可能就会出现问题&#xff0c;这个就是线程安全问题&#xff08;或者称线程不安全问题&#xff09;&#xff0c;简而言之就是&#xff1a;线程安全问题是由于多线程出现的问题&#xff0c;原因…

NodeJs 桌面开发学习 electron.js (一)

今天开始学习NodeJs 关于 桌面应用的内容&#xff0c;长期目标是 React electron 实现一个桌面应用。今天先实现一个简单的目标&#xff0c;搭建一个Electron ts 项目架构&#xff0c;并实现主业务线程 和前端渲染线程的交互一、代码结构和配置例子项目结构大致如下&#xff…

diffusion model(1.4) 相关论文阅读清单

以下是阅读清单&#xff1a; 《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》扩散模型&#xff0c;arxiv链接《Denoising Diffusion Probabilistic Models》DDPM论文 arxiv链接

ESP32-C3_SMARTCAR

前言: 前面用stm32f103c8t6 rt-thread 写了个智能小车程序 这章用esp32-c3 重新来遍 1&#xff1a;环境 vscodeidf5.4 esp32-3c 找到一块MIN的底板 凑合用&#xff08;138 cm左右&#xff09; 一个L298N 一个船型开关&#xff0c; 一个665mm 2脚按钮 锂电池 186502 及电池盒&a…

消费者API

目录独立消费者案例&#xff08;订阅主题&#xff09;独立消费者案例&#xff08;订阅分区&#xff09;消费者组案例独立消费者案例&#xff08;订阅主题&#xff09; package com.tsg.kafka.consumer;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.ap…

C# NX二次开发:操作按钮控件Button和标签控件Label详解

大家好&#xff0c;今天介绍ug二次开发过程中的一个叫操作按钮的控件&#xff0c;这个控件在块UI编辑器中可以使用。 ​ Button这个控件的属性和方法如下所示&#xff1a; namespace NXOpen.BlockStyler { public class Label : UIBlock { protected intern…

Vue.prototype 的作用

在 Vue.js 中&#xff0c;Vue.prototype 是用来向所有 Vue 实例添加属性或方法的机制。通过它添加的属性或方法可以在所有 Vue 组件实例中通过 this 访问。主要作用添加全局方法或属性&#xff1a;可以在所有组件中使用的工具方法或常量扩展 Vue 功能&#xff1a;添加 Vue 本身…

Javaee 多线程 --进程和线程之间的区别和联系

文章目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnable(接口)&#xff0c;重写run继承Thread,重写run,但是使用匿名内部类实现Runnable(接口)&#xff0c;重写run&#xff0c;但是使用匿名内部类使用lambda表达式请说明Thread类中run和…

企业如何让内部视频仅限指定域名播放,确保视频不被泄露?

在数字化办公时代&#xff0c;企业内部的培训视频、产品演示或机密会议录像等敏感内容&#xff0c;一旦被非法传播或泄露&#xff0c;可能带来严重的商业风险。如何确保这些视频只能在公司官网或指定域名播放&#xff0c;防止被恶意下载、盗链或二次传播&#xff1f;今天介绍一…

端口映射原理操作详解教程:实现外网访问内网服务,本地路由器端口映射公网ip和软件端口映射域名2种方法

端口映射作为一种不同网络间通信的关键网络技术&#xff0c;在远程访问和内外网连接服务需求日益增长的如今&#xff0c;理解端口映射的原理和设置方法是确保网络服务可用性的必要技能。本文将深入探讨端口映射的基本概念、路由器端口映射设置步骤以及无公网IP用端口映射软件映…

【PyTorch】多对象分割项目

对象分割任务的目标是找到图像中目标对象的边界。实际应用例如自动驾驶汽车和医学成像分析。这里将使用PyTorch开发一个深度学习模型来完成多对象分割任务。多对象分割的主要目标是自动勾勒出图像中多个目标对象的边界。 对象的边界通常由与图像大小相同的分割掩码定义&#xf…

SSH 使用密钥登录服务器

用这种方法远程登陆服务器的时候无需手动输入密码 具体步骤 客户端通过 ssh-keygen 生成公钥和私钥 ssh-keygen -t rsa 生成的时候会有一系列问题&#xff0c;根据自己的需要选择就行。生成的结果为两个文件&#xff1a; 上传公钥至服务器&#xff0c;上述两个文件一般在客户…

MySQL 8.4 企业版启用TDE功能和表加密

一、系统环境操作系统&#xff1a;Ubuntu 24.04 数据库:8.4.4-commercial for Linux on x86_64 (MySQL Enterprise Server - Commercial)二、安装TDE组件前提&#xff1a;检查组件文件是否存在ls /usr/lib/mysql/plugin/component_keyring_encrypted_file.so1.配置全局清单文件…

【Altium designer】导出的原理图PDF乱码异常的解决方法

一、有些电源名字无法显示或器件丢失 解决办法 (1)首先AD18以及以上的新版本AD不存在该问题。 (2)其次AD17以及更旧版本的AD很可能遇到该问题,参考如下博客笔记进行操作即可: 大致的操作如下:DXP → Preferences → Schematic → Options里面“Render Text with GDI+”…

4.Ansible自动化之-部署文件到主机

4 - 部署文件到受管主机 实验环境 先通过以下命令搭建基础环境&#xff08;创建工作目录、配置 Ansible 环境和主机清单&#xff09;&#xff1a; # 在控制节点&#xff08;controller&#xff09;上创建web目录并进入&#xff0c;作为工作目录 [bqcontroller ~]$ mkdir web &a…

Vuex的使用

Vuex 超详细使用教程&#xff08;从入门到精通&#xff09;一、Vuex 是什么&#xff1f;Vuex 是专门为 Vue.js 设计的状态管理库&#xff0c;它采用集中式存储管理应用的所有组件的状态。简单来说&#xff0c;Vuex 就是一个"全局变量仓库"&#xff0c;所有组件都可以…

pytorch 数据预处理,加载,训练,可视化流程

流程定义自定义数据集类定义训练和验证的数据增强定义模型、损失函数和优化器训练循环&#xff0c;包括验证训练可视化整个流程模型评估高级功能扩展混合精度训练​分布式训练​{:width“50%” height“50%”} 定义自定义数据集类 # #1. 自定义数据集类 # class CustomImageD…

Prompt工程:OCR+LLM文档处理的精准制导系统

在PDF OCR与大模型结合的实际应用中&#xff0c;很多团队会发现一个现象&#xff1a;同样的OCR文本&#xff0c;不同的Prompt设计会产生截然不同的提取效果。有时候准确率能达到95%&#xff0c;有时候却只有60%。这背后的关键就在于Prompt工程的精细化程度。 &#x1f3af; 为什…

RecSys:粗排模型和精排特征体系

粗排 在推荐系统链路中&#xff0c;排序阶段至关重要&#xff0c;通常分为召回、粗排和精排三个环节。粗排作为精排前的预处理阶段&#xff0c;需要在效果和性能之间取得平衡。 双塔模型 后期融合&#xff1a;把用户、物品特征分别输入不同的神经网络&#xff0c;不对用户、…

spring声明式事务,finally 中return对事务回滚的影响

finally 块中使用 return 是一个常见的编程错误&#xff0c;它会&#xff1a; 跳过正常的事务提交流程。吞掉异常&#xff0c;使错误处理失效 导致不可预测的事务行为Java 中 finally 和 return 的执行机制&#xff1a;1. finally 块的基本特性 在 Java 中&#xff0c;finally …