软件注册机 | QT给自己的桌面软件实现软件注册码功能

之前做的一个项目,想要给软件做一个注册码功能。当软件发布之后,不想给所有人用,这时就可以通过注册机给软件生成授权码来软件加密。整个过程实现分为两大步骤,一是在自己的软件打开时,增加一段判断逻辑;二是写一个软件注册机,对于给定的机器码生成授权码,并且设置授权到期时间。这里也说明一下,本文实现软件注册码的功能主要是基于注册表
大体实现思路是获取到机器的CPU信息、MAC信息生成独一无二的机器码,之后使用密钥对其做md5加密,最后为该机器设置一个过期时间,并对其进行编码,拼接在加密后的字符后,作为授权码。

1. 在自己的项目中增加判断逻辑

以下是一些工具函数

// 获取MAC地址信息
QString get_mac_id()
{QList<QNetworkInterface> nets = QNetworkInterface::allInterfaces();int nCnt = nets.count();QString strMacAddr = "";for(int i = 0; i < nCnt; i++){if(nets[i].flags().testFlag(QNetworkInterface::IsUp) &&nets[i].flags().testFlag(QNetworkInterface::IsRunning) &&!nets[i].flags().testFlag(QNetworkInterface::IsLoopBack)){for(int j = 0; j < nets[i].addressEntries().size(); j++){if(nets[i].addressEntries().at(j).ip() != QHostAddress::LocalHost &&nets[i].addressEntries().at(j).ip().protocol() == QAbstractSocket::IPv4Protocol){strMacAddr = nets[i].hardwareAddress();}}}}strMacAddr.remove(':');return strMacAddr;
}// 获取CPU信息
QString get_cpu_id(){QString strCpuId = "";unsigned int dwBuf[4] = { 0 };unsigned long long ret = 0;__cpuid((int*)(void*)dwBuf, 1);ret = dwBuf[3];ret = ret << 32;QString str0 = QString::number(dwBuf[3], 16).toUpper();QString str0_1 = str0.rightJustified(8, '0');QString str1 = QString::number(dwBuf[0], 16).toUpper();QString str1_1 = str1.rightJustified(8, '0');strCpuId = str0_1 + str1_1;return strCpuId;
}// 获得独一无二的机器码
QString get_machine_code()
{QString cpuid = get_cpu_id();QString macid = get_mac_id();QString UniqueCode = cpuid + macid;QString MachineCode = "";for(int i = 0; i < UniqueCode.size(); i++){MachineCode = MachineCode + UniqueCode[i];if((i+1)%4==0 && i+1!=UniqueCode.size()){MachineCode = MachineCode + "-";}}return MachineCode;}// 加入公钥
QString get_visible_key(){QString machinecode = get_machine_code();QString Authorkey1 = "key1";QString Authorkey2 = "key2";QString ciphertext = Authorkey1+ "-" + machinecode + "-" + Authorkey2;return ciphertext;
}// 获得加密后的密码
QString get_md5_key(){QString ciphertext = get_visible_key();QString md5Str = QCryptographicHash::hash(ciphertext.toLatin1(),QCryptographicHash::Md5).toHex();return md5Str;
}
1.1 判断注册表中是否有值,值是否过期

声明下面的函数,可以判断到当前机器是否已被授权

bool is_authorized(){QString md5pwd = get_md5_key();QSettings setting(registry_key, QSettings::NativeFormat);QString mypwd = setting.value("AuthKey", "").toString();mypwd = mypwd.split("-")[0];if(mypwd == md5pwd){return true;}else{return false;}
}
1.2 在main方法中循环调用授权窗口,判断授权码是否正确
int main(int argc, char *argv[])
{QApplication a(argc, argv);// 设置程序的字体大小QFont font = a.font();font.setPointSize(10);a.setFont(font);QString key = "AuthKey";AuthDialog authDialog;   // 授权页authDialog.setMachineCode(get_machine_code());if(isExpire(key)){authDialog.changeTip();}while (is_authorized() == false) {if (authDialog.exec() == QDialog::Accepted) {if (authDialog.authorized) {break; // 授权成功,跳出循环} else {QMessageBox::warning(nullptr, "授权失败", "授权码验证失败,请重试");authDialog.clearPage();  // 界面恢复原始}} else {return 0; // 用户取消授权,退出程序}}MainWindow w;w.show();return a.exec();
}
1.3 授权窗口

授权窗口中针对“确定”按钮绑定了槽函数,点确定的时候,会调用验证函数,判断授权码是否正确,如果正确的话,会设置标志位位true,成功进入软件。否则返回false,继续弹窗。

void AuthDialog::on_buttonBox_accepted()
{if(validateKey()){authorized = true;save_authorization_info(ui->authCode->text());accept();}
}bool AuthDialog::validateKey(){QString authKey = ui->authCode->text();if(authKey.contains("-") && (authKey.split("-").length() >= 2)){QString encodedExpireTime = authKey.split("-")[1];QString expireTime = decode(encodedExpireTime);   // 解码出时间 形式是20240616这样QDate expireDate = QDate::fromString(expireTime, "yyyyMMdd");QDate currentDate = QDate::currentDate();if(currentDate > expireDate){   // 授权码已经过期return false;}}QString authCode = authKey.split("-")[0];return authCode == get_md5_key();    // 时间没过期并且授权码经过验证 此时才能使用
}void AuthDialog::on_buttonBox_rejected()
{reject();
}void AuthDialog::setMachineCode(QString machineCode){ui->machineCode->setText(machineCode);
}
void AuthDialog::clearPage(){ui->authCode->setText("");
}// 加入公钥
QString AuthDialog::get_visible_key(){QString machinecode = ui->machineCode->text();//    m_str_machine_code = machinecode;QString Authorkey1 = "key1";QString Authorkey2 = "key2";QString ciphertext = Authorkey1+ "-" + machinecode + "-" + Authorkey2;return ciphertext;
}// 获得加密后的密码
QString AuthDialog::get_md5_key(){QString ciphertext = get_visible_key();QString md5Str = QCryptographicHash::hash(ciphertext.toLatin1(),QCryptographicHash::Md5).toHex();return md5Str;
}void AuthDialog::save_authorization_info(QString md5_key)
{QSettings setting(registry_key, QSettings::NativeFormat);setting.setValue("AuthKey", md5_key);
}void AuthDialog::changeTip(){ui->textEdit->setText("您的授权码已过期,请重新将机器码发送给管理员进行授权");
}QString AuthDialog::encode(QByteArray data){return data.toBase64();
}QString AuthDialog::decode(QString encoded){return QString::fromUtf8((QByteArray::fromBase64(encoded.toUtf8())));
}

2. 软件注册机

2.1 对于传入的机器码,做合法性校验
bool MainWindow::validateMachineKey(){QString machineCode = ui->machineCode->text();if(machineCode == ""){return false;}QRegularExpression regex("^([A-F0-9]{4}-){6}[A-F0-9]{4}$");QRegularExpressionMatch match = regex.match(machineCode);return match.hasMatch();
}
2.2 对机器码加密钥,使用md5加密处理,将加密后的字符与过期时间做拼接
QString MainWindow::get_md5_key(){QString ciphertext = get_visible_key();QString md5Str = QCryptographicHash::hash(ciphertext.toLatin1(),QCryptographicHash::Md5).toHex();QString expireTime;if(ui->checkBox_forever->isChecked()){expireTime = "30240616";}else{expireTime = ui->dateEdit->date().toString("yyyyMMdd");}return md5Str + "-" + encode(expireTime.toUtf8());
}// 使用 Base64编码
QString MainWindow::encode(QByteArray data){return data.toBase64();
}

在经过上面的步骤,就可以实现给自己的软件加密了!
说明:
(1)步骤1放到一个项目中,步骤2放到一个项目中,最后呈现结果是两个软件。
(2)保证密钥是相同的,否则会在授权判断时失败。
写在最后,有任何问题欢迎与我沟通交流(><)

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

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

相关文章

GD32中断

1.什么是中断&#xff1a;打断现在正在做的事&#xff0c;去执行其他事。 2.ARM异常中断结构 3.中断向量编号。中断向量是 进行了映射的&#xff0c;直接映射到 flash中的地址。 4.中断执行结构。向量里面保存的是执行函数的地址。&#xff08;具体可在编译完后的map文件中查看…

三菱FX3U模拟量产品的介绍

FX3u可编程控制器模拟量产品包括&#xff1a;特殊适配器、特殊功能模块的连接 1、连接在FX3U可编程控制器的左侧。 2、连接特殊适配器时&#xff0c;需要功能扩展板。 3、最多可以连接4台模拟量特殊适配器。 4、使用高速输入输出特殊适配器时&#xff0c;请将模拟量特殊适配器连…

WHAT - webpack、vite(rollup)、rsbuild 对比

目录 一、分析二、其他阅读 一、分析 以下是 Webpack、Vite 和 rsbuild 在多个维度上的比较分析表格&#xff1a; 维度WebpackVitersbuild核心语言/技术使用 JavaScript 和 Node.js基于 JavaScript/TypeScript&#xff0c;依赖原生 ESM 和浏览器支持使用 Rust 编写&#xff0…

软件测试丨Appium 源码分析与定制

在本文中&#xff0c;我们将深入Appium的源码&#xff0c;探索它的底层架构、定制化使用方法和给软件测试带来的优势。我们将详细介绍这些技术如何解决实际问题&#xff0c;并与大家分享一些实用的案例&#xff0c;以帮助读者更好地理解和应用这一技术。 Appium简介 什么是App…

【PlantUML系列】流程图(四)

目录 目录 一、基础用法 1.1 开始和结束 1.2 操作步骤 1.3 条件判断 1.4 并行处理 1.5 循环 1.6 分区 1.7 泳道 一、基础用法 1.1 开始和结束 开始一般使用start关键字&#xff1b;结束一般使用stop/end关键字。基础用法包括&#xff1a; start ... stopstart ...…

Linux 串口编程

目录 前言一、tty体系二、串口硬件基础知识三、Linux下的串口编程3.1 打开串口3.2 从串口读写数据,问题1、2的诞生3.3 关闭串口3.4 串口配置3.4.1 获取/设置串口的参数3.4.2 设置波特率3.4.3 设置控制模式标志3.4.4 设置本地模式标志3.4.5 设置输入模式标志3.4.6 设置输出模式标…

️【设计模式】之单例模式详解:创建者模式中的一颗“明珠”

全文目录&#xff1a; 开篇语&#x1f3af; 什么是单例模式&#xff1f;&#x1f5c2;️ 单例模式的关键特性&#x1f511; 单例模式的实现方式1. &#x1f331; 懒汉式单例&#xff08;Lazy Initialization&#xff09;2. &#x1f512; 懒汉式单例&#xff08;线程安全版&…

idea压缩js,css

这是需要的jar包(文章顶部也可以下载) 地址:https://download.csdn.net/download/yuzheh521/90109966?spm1001.2101.3001.9500 压缩js arguments: -jar E:\swj\jar_packages\css_js_compress\yuicompressor-2.4.8.jar --type js --charset utf-8 $FilePath$ -o $FileNameWith…

ASP.NET |日常开发中连接Oracle数据库详解

ASP.NET &#xff5c;日常开发中连接Oracle数据库详解 前言一、安装和配置 Oracle 数据访问组件1.1 安装ODP.NET&#xff08;Oracle Data Provider for.NET&#xff09;&#xff1a;1.2 引用相关程序集&#xff1a; 二、配置连接字符串2.1 连接字符串的基本组成部分&#xff1a…

【linux系统】基础开发工具(yum、Vim)

1. 软件包管理器 1.1 什么是软件包 在Linux下安装软件, ⼀个通常的办法是下载到程序的源代码, 并进⾏编译, 得到可执⾏程序. 但是这样太麻烦了, 于是有些⼈把⼀些常⽤的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在⼀个服务器上, 通过包管理器可以很⽅便的…

C语言:define定义常量和定义宏(详解)

本篇博客给大家带来的是#define定义常量和#define定义宏的方法 &#x1f41f;&#x1f41f;文章专栏&#xff1a;C语言 &#x1f680;&#x1f680;若有问题评论区下讨论&#xff0c;我会及时回答 ❤❤欢迎大家点赞、收藏、分享 你们的支持就是我创造的动力 今日思想&#xff1…

Let up bring up a linux.part2 [十一]

之前的篇幅中我们已经将 Linux 内核 bringup 起来了&#xff0c;不知道大家有没有去尝试将根文件系统运行起来&#xff0c;今天我就带领大家完成这个事情&#xff0c;可以跟着下面的步骤一步步来完成&#xff1a; 在这里我们使用 busybox 构建 rootfs&#xff1a; 下载 busyb…

使用GO--Swagger生成文档

概述 在前后端分离的项目中&#xff0c;后端配置swagger可以很好的帮助前端人员了解后端接口参数和数据传输。go-swagger 是一个功能全面且高性能的Go语言实现工具包&#xff0c;用于处理Swagger 2.0&#xff08;即OpenAPI 2.0&#xff09;规范。它提供了丰富的工具集&#x…

pushgateway HA高可用方案

未经本人同意不得转载&#xff0c;若引用请附上原文链接。 项目使用flink来处理kafka中的无界流数据&#xff0c;采用的是flink on yarn的模式部署flink任务。最近做flink任务的监控过程中&#xff0c;踩了一些坑。下面是过程&#xff0c;只想看最终方案的直接拉到最后。 先说…

01-Chromedriver下载与配置(mac)

下载地址&#xff1a; 这里我用的最后一个&#xff0c;根据自己chrome浏览器选择相应的版本号即可 ChromeDriver官网下载地址&#xff1a;https://sites.google.com/chromium.org/driver/downloads ChromeDriver官网最新版下载地址&#xff1a;https://googlechromelabs.git…

SSH连接报错,Corrupted MAC on input 解决方法

问题描述 客户在windows CMD中SSH连接失败&#xff0c;报错: Corrupted MAC on input ssh_dispatch_run_fatal: Connection to x.x.x.x port 22: message authentication code incorrect值得注意的是&#xff0c;客户通过别的机器做SSH连接可以成功&#xff0c;使用putty, mo…

pom.xml文件在IDEA中不是蓝色的“M”标志

通常是因为IDEA没有将该文件识别为Maven项目&#xff0c;这会导致IDEA无法自动处理pom.xml中的依赖管理。 解决方法&#xff1a;手动添加为Maven项目 选中pom.xml文件&#xff0c;鼠标右键点击&#xff0c;选择“Add as Maven Project”。等待几秒钟&#xff0c;IDEA会读取po…

使用docker-compose安装Milvus向量数据库及Attu可视化连接工具

首先确保系统已经安装上了docker 然后去https://github.com/docker/compose/releases/下载安装docker-compose 跟随自己下系统和服务器情况下载 上传到服务器 mv docker-compose-linux-aarch64 docker-compose chmod x docker-compose2.dockr-compose命令 docker-compose …

计算机组成原理(三):函数调用

在汇编语言中&#xff0c;函数调用的核心思想与高阶语言类似&#xff0c;涉及栈的管理、寄存器的使用以及程序计数器的跳转。具体而言&#xff0c;函数调用的过程主要包括以下几个方面&#xff1a;栈操作、寄存器的保存与恢复、参数传递、返回值的处理等。 函数调用的过程 &a…

Conda + JuiceFS :增强 AI 开发环境共享能力

Conda 是当前 AI 应用开发领域中非常流行的环境和包管理系统&#xff0c;因其能够简单便捷地创建与系统资源相隔离的虚拟环境广受欢迎。 Conda 支持在不同的操作系统上重建相同的工作环境&#xff0c;但在环境共享复用方面仍存在一些挑战。比如&#xff0c;在不同机器上复用相…