在很多商业软件中,需要提供一些可以试运行的版本,这样就需要配套密钥机制来控制,纵观大部分的试用版软件,基本上采用以下几种机制来控制。
1:远程联网激活,每次启动都联网查看使用时间等,这种方法最完美,缺点是没法联网的设备就歇菜了。
2:通过获取本地的硬盘+CPU等硬件的编号,做一个运算,生成一个激活码,超过半数的软件会采用此方法,缺点是不能自由控制软件的其他参数,比如软件中添加的设备数量的控制。
3:设定一个运行到期时间+数量限制+已运行时间的密钥文件,发给用户配套软件使用,缺点是如果仅仅设置的是运行到期时间,用户可以更改电脑时间来获取更长的使用时间,在电脑不联网的情况下。
本demo采用抛砖引玉的形式,用第三种方法来实现,密钥文件采用最简单的异或加密,可以自行改成其他加密方法。
完整代码下载地址:https://download.csdn.net/download/feiyangqingyun/10975625
核心代码:
1 #include "frmmain.h" 2 #include "ui_frmmain.h" 3 #include "qmessagebox.h" 4 #include "qfile.h" 5 6 frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) 7 { 8 ui->setupUi(this); 9 this->initForm(); 10 } 11 12 frmMain::~frmMain() 13 { 14 delete ui; 15 } 16 17 void frmMain::initForm() 18 { 19 QStringList min; 20 min << "1" << "5" << "10" << "20" << "30"; 21 for (int i = 1; i <= 24; i++) { 22 min << QString::number(i * 60); 23 } 24 25 ui->cboxMin->addItems(min); 26 ui->cboxMin->setCurrentIndex(1); 27 ui->dateEdit->setDate(QDate::currentDate()); 28 29 for (int i = 5; i <= 150; i = i + 5) { 30 ui->cboxCount->addItem(QString("%1").arg(i)); 31 } 32 } 33 34 QString frmMain::getXorEncryptDecrypt(const QString &data, char key) 35 { 36 //采用异或加密,也可以自行更改算法 37 QByteArray buffer = data.toLatin1(); 38 int size = buffer.size(); 39 for (int i = 0; i < size; i++) { 40 buffer[i] = buffer.at(i) ^ key; 41 } 42 43 return QLatin1String(buffer); 44 } 45 46 void frmMain::on_btnOk_clicked() 47 { 48 bool useDate = ui->ckDate->isChecked(); 49 bool useRun = ui->ckRun->isChecked(); 50 bool useCount = ui->ckCount->isChecked(); 51 52 if (!useDate && !useRun && !useCount) { 53 if (QMessageBox::question(this, "询问", "确定要生成没有任何限制的密钥吗?") != QMessageBox::Yes) { 54 return; 55 } 56 } 57 58 QString strDate = ui->dateEdit->date().toString("yyyy-MM-dd"); 59 QString strRun = ui->cboxMin->currentText(); 60 QString strCount = ui->cboxCount->currentText(); 61 QString key = QString("%1|%2|%3|%4|%5|%6").arg(useDate).arg(strDate).arg(useRun).arg(strRun).arg(useCount).arg(strCount); 62 63 QFile file(QApplication::applicationDirPath() + "/key.db"); 64 file.open(QFile::WriteOnly | QIODevice::Text); 65 file.write(getXorEncryptDecrypt(key, 110).toLatin1()); 66 file.close(); 67 QMessageBox::information(this, "提示", "生成密钥成功,将 key.db 文件拷贝到对应目录即可!"); 68 } 69 70 void frmMain::on_btnClose_clicked() 71 { 72 this->close(); 73 }
使用demo封装类代码:
1 #include "appkey.h" 2 #include "qmutex.h" 3 #include "qfile.h" 4 #include "qtimer.h" 5 #include "qdatetime.h" 6 #include "qapplication.h" 7 #include "qmessagebox.h" 8 9 AppKey *AppKey::self = NULL; 10 AppKey *AppKey::Instance() 11 { 12 if (!self) { 13 QMutex mutex; 14 QMutexLocker locker(&mutex); 15 if (!self) { 16 self = new AppKey; 17 } 18 } 19 20 return self; 21 } 22 23 AppKey::AppKey(QObject *parent) : QObject(parent) 24 { 25 keyData = ""; 26 keyUseDate = false; 27 keyDate = "2017-01-01"; 28 keyUseRun = false; 29 keyRun = 1; 30 keyUseCount = false; 31 keyCount = 10; 32 33 timer = new QTimer(this); 34 timer->setInterval(1000); 35 connect(timer, SIGNAL(timeout()), this, SLOT(checkTime())); 36 startTime = QDateTime::currentDateTime(); 37 } 38 39 void AppKey::start() 40 { 41 //判断密钥文件是否存在,不存在则从资源文件复制出来,同时需要设置文件写权限 42 QString keyName = qApp->applicationDirPath() + "/key.db"; 43 QFile keyFile(keyName); 44 if (!keyFile.exists() || keyFile.size() == 0) { 45 QMessageBox::critical(0, "错误", "密钥文件丢失,请联系供应商!"); 46 exit(0); 47 } 48 49 //读取密钥文件 50 keyFile.open(QFile::ReadOnly); 51 keyData = keyFile.readLine(); 52 keyFile.close(); 53 54 //将从注册码文件中的密文解密,与当前时间比较是否到期 55 keyData = getXorEncryptDecrypt(keyData, 110); 56 QStringList data = keyData.split("|"); 57 58 if (data.count() != 6) { 59 QMessageBox::critical(0, "错误", "注册码文件已损坏,程序将自动关闭!"); 60 exit(0); 61 } 62 63 keyUseDate = (data.at(0) == "1" ? true : false); 64 keyDate = data.at(1); 65 keyUseRun = (data.at(2) == "1" ? true : false); 66 keyRun = data.at(3).toInt(); 67 keyUseCount = (data.at(4) == "1" ? true : false); 68 keyCount = data.at(5).toInt(); 69 70 //如果启用了时间限制 71 if (keyUseDate) { 72 QString nowDate = QDate::currentDate().toString("yyyy-MM-dd"); 73 if (nowDate > keyDate) { 74 QMessageBox::critical(0, "错误", "软件已到期,请联系供应商更新注册码!"); 75 exit(0); 76 } 77 } 78 79 //如果启用了运行时间显示 80 if (keyUseRun) { 81 timer->start(); 82 } 83 } 84 85 void AppKey::stop() 86 { 87 timer->stop(); 88 } 89 90 void AppKey::checkTime() 91 { 92 //找出当前时间与首次启动时间比较 93 QDateTime now = QDateTime::currentDateTime(); 94 if (startTime.secsTo(now) >= (keyRun * 60)) { 95 QMessageBox::critical(0, "错误", "试运行时间已到,请联系供应商更新注册码!"); 96 exit(0); 97 } 98 } 99 100 QString AppKey::getXorEncryptDecrypt(const QString &data, char key) 101 { 102 //采用异或加密,也可以自行更改算法 103 QByteArray buffer = data.toLatin1(); 104 int size = buffer.size(); 105 for (int i = 0; i < size; i++) { 106 buffer[i] = buffer.at(i) ^ key; 107 } 108 109 return QLatin1String(buffer); 110 } 111 112 bool AppKey::checkCount(int count) 113 { 114 if (keyUseCount) { 115 if (count >= keyCount) { 116 QMessageBox::critical(0, "错误", "设备数量超过限制,请联系供应商更新注册码!"); 117 return false; 118 } 119 } 120 121 return true; 122 }