Qt編寫金鑰生成器+使用demo(開源)
阿新 • • 發佈:2019-02-26
在很多商業軟體中,需要提供一些可以試執行的版本,這樣就需要配套金鑰機制來控制,縱觀大部分的試用版軟體,基本上採用以下幾種機制來控制。
1:遠端聯網啟用,每次啟動都聯網檢視使用時間等,這種方法最完美,缺點是沒法聯網的裝置就歇菜了。
2:通過獲取本地的硬碟+CPU等硬體的編號,做一個運算,生成一個啟用碼,超過半數的軟體會採用此方法,缺點是不能自由控制軟體的其他引數,比如軟體中新增的裝置數量的控制。
3:設定一個執行到期時間+數量限制+已執行時間的金鑰檔案,發給使用者配套軟體使用,缺點是如果僅僅設定的是執行到期時間,使用者可以更改電腦時間來獲取更長的使用時間,在電腦不聯網的情況下。
本demo採用拋磚引玉的形式,用第三種方法來實現,金鑰檔案採用最簡單的異或加密,可以自行改成其他加密方法。
完整程式碼下載地址:
核心程式碼:
#include "frmmain.h" #include "ui_frmmain.h" #include "qmessagebox.h" #include "qfile.h" frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) { ui->setupUi(this); this->initForm(); } frmMain::~frmMain() { delete ui; } void frmMain::initForm() { QStringList min; min << "1" << "5" << "10" << "20" << "30"; for (int i = 1; i <= 24; i++) { min << QString::number(i * 60); } ui->cboxMin->addItems(min); ui->cboxMin->setCurrentIndex(1); ui->dateEdit->setDate(QDate::currentDate()); for (int i = 5; i <= 150; i = i + 5) { ui->cboxCount->addItem(QString("%1").arg(i)); } } QString frmMain::getXorEncryptDecrypt(const QString &data, char key) { //採用異或加密,也可以自行更改演算法 QByteArray buffer = data.toLatin1(); int size = buffer.size(); for (int i = 0; i < size; i++) { buffer[i] = buffer.at(i) ^ key; } return QLatin1String(buffer); } void frmMain::on_btnOk_clicked() { bool useDate = ui->ckDate->isChecked(); bool useRun = ui->ckRun->isChecked(); bool useCount = ui->ckCount->isChecked(); if (!useDate && !useRun && !useCount) { if (QMessageBox::question(this, "詢問", "確定要生成沒有任何限制的金鑰嗎?") != QMessageBox::Yes) { return; } } QString strDate = ui->dateEdit->date().toString("yyyy-MM-dd"); QString strRun = ui->cboxMin->currentText(); QString strCount = ui->cboxCount->currentText(); QString key = QString("%1|%2|%3|%4|%5|%6").arg(useDate).arg(strDate).arg(useRun).arg(strRun).arg(useCount).arg(strCount); QFile file(QApplication::applicationDirPath() + "/key.db"); file.open(QFile::WriteOnly | QIODevice::Text); file.write(getXorEncryptDecrypt(key, 110).toLatin1()); file.close(); QMessageBox::information(this, "提示", "生成金鑰成功,將 key.db 檔案拷貝到對應目錄即可!"); } void frmMain::on_btnClose_clicked() { this->close(); }
使用demo封裝類程式碼:
#include "appkey.h"
#include "qmutex.h"
#include "qfile.h"
#include "qtimer.h"
#include "qdatetime.h"
#include "qapplication.h"
#include "qmessagebox.h"
AppKey *AppKey::self = NULL;
AppKey *AppKey::Instance()
{
if (!self) {
QMutex mutex;
QMutexLocker locker(&mutex);
if (!self) {
self = new AppKey;
}
}
return self;
}
AppKey::AppKey(QObject *parent) : QObject(parent)
{
keyData = "";
keyUseDate = false;
keyDate = "2017-01-01";
keyUseRun = false;
keyRun = 1;
keyUseCount = false;
keyCount = 10;
timer = new QTimer(this);
timer->setInterval(1000);
connect(timer, SIGNAL(timeout()), this, SLOT(checkTime()));
startTime = QDateTime::currentDateTime();
}
void AppKey::start()
{
//判斷金鑰檔案是否存在,不存在則從資原始檔複製出來,同時需要設定檔案寫許可權
QString keyName = qApp->applicationDirPath() + "/key.db";
QFile keyFile(keyName);
if (!keyFile.exists() || keyFile.size() == 0) {
QMessageBox::critical(0, "錯誤", "金鑰檔案丟失,請聯絡供應商!");
exit(0);
}
//讀取金鑰檔案
keyFile.open(QFile::ReadOnly);
keyData = keyFile.readLine();
keyFile.close();
//將從註冊碼檔案中的密文解密,與當前時間比較是否到期
keyData = getXorEncryptDecrypt(keyData, 110);
QStringList data = keyData.split("|");
if (data.count() != 6) {
QMessageBox::critical(0, "錯誤", "註冊碼檔案已損壞,程式將自動關閉!");
exit(0);
}
keyUseDate = (data.at(0) == "1" ? true : false);
keyDate = data.at(1);
keyUseRun = (data.at(2) == "1" ? true : false);
keyRun = data.at(3).toInt();
keyUseCount = (data.at(4) == "1" ? true : false);
keyCount = data.at(5).toInt();
//如果啟用了時間限制
if (keyUseDate) {
QString nowDate = QDate::currentDate().toString("yyyy-MM-dd");
if (nowDate > keyDate) {
QMessageBox::critical(0, "錯誤", "軟體已到期,請聯絡供應商更新註冊碼!");
exit(0);
}
}
//如果啟用了執行時間顯示
if (keyUseRun) {
timer->start();
}
}
void AppKey::stop()
{
timer->stop();
}
void AppKey::checkTime()
{
//找出當前時間與首次啟動時間比較
QDateTime now = QDateTime::currentDateTime();
if (startTime.secsTo(now) >= (keyRun * 60)) {
QMessageBox::critical(0, "錯誤", "試執行時間已到,請聯絡供應商更新註冊碼!");
exit(0);
}
}
QString AppKey::getXorEncryptDecrypt(const QString &data, char key)
{
//採用異或加密,也可以自行更改演算法
QByteArray buffer = data.toLatin1();
int size = buffer.size();
for (int i = 0; i < size; i++) {
buffer[i] = buffer.at(i) ^ key;
}
return QLatin1String(buffer);
}
bool AppKey::checkCount(int count)
{
if (keyUseCount) {
if (count >= keyCount) {
QMessageBox::critical(0, "錯誤", "裝置數量超過限制,請聯絡供應商更新註冊碼!");
return false;
}
}
return true;
}