每次启动软件时会读取注册文件,若不存在则提示输入激活码,进行注册。若文件存在,则解析文件验证文件合法性,计算剩余使用期限。
为了使每个激活码仅对应一个用户(机器),我们的激活码应当绑定设备,因此应包含MAC地址信息。
激活界面,会显示当前的机器码,机器码根据本机MAC地址通过相应算法生成,因此每个用户的机器码都不同。用户将机器码发送给厂商,厂商根据机器码和使用期限生成相应的激活码,发送给用户,用户输入激活码完成注册。注册后会生成注册文件,文件为二进制加密文件,存放注册日期,使用期限等信息,用户无法直接篡改,且若文件缺失需要重新注册。
由一个机器码输入框、一个有效期输入框、一个激活码生成框以及生成按钮组成。
厂家需要输入用户给出的机器码,输入要赋予的有效期限,点击按钮就能生成激活码。
机器码的获取在 验证端(客户端) 中会提及。
下方为用随机数生成的密码表,建议大家自己重新生成密码表。
uint8_t pwd[256]={23,95,39,51,15,49,18,20,78,45,24,4,74,113,100,123,
0,37,34,121,127,108,25,37,37,56,20,75,34,8,112,87,
19,117,101,4,24,35,82,107,93,51,95,108,28,33,88,6,
23,26,25,65,84,56,62,33,120,1,65,87,47,51,39,43,
78,23,41,43,95,26,76,50,121,96,75,8,13,24,23,115,
40,99,123,72,52,87,5,81,117,115,42,38,59,26,38,94,
105,28,6,87,18,75,93,107,101,62,19,18,7,37,89,73,
23,92,12,59,46,48,59,10,70,7,81,59,43,77,95,107,
72,66,67,59,48,106,126,120,31,80,105,99,127,9,96,72,
70,27,47,67,32,80,33,64,112,56,13,27,10,71,63,63,
100,59,91,8,1,65,9,35,14,90,71,90,123,37,21,47,
16,62,110,69,39,55,75,30,113,122,53,73,22,29,111,29,
114,89,27,85,76,84,52,85,76,62,26,60,109,90,44,21,
20,46,115,108,19,35,58,55,55,78,27,49,12,69,105,74,
109,91,90,108,127,95,76,53,53,112,74,72,79,26,109,102,
21,10,25,68,67,17,29,22,59,80,39,97,120,104,0,109};
QString getActivationCode(QString machineCode,ing yxq)//machineCode机器码,yxq有效期:天
{
QString sj=QDate::currentDate().toString("yyMMdd");//当前日期,由此也说明了激活码仅当天有效
//中间为激活码生成算法,不必深究
QString Activation;
for(int j=0;j<6;j++)
{
int tempCode;
tempCode=pwd[machineCode.mid(j*2,2).toInt(nullptr,16)]<<sj.mid(j,1).toInt();
Activation.append(tenToHexL(tempCode));
}
QString Activation2;
for(int k=0;k<5;k++)
{
int tempCode2;
tempCode2=Activation.mid(4*k+4,4).toInt(nullptr,16)>>tenToBin(sj.mid(4,2).toInt()).mid(k,1).toInt();
Activation2.append(tenToHexL(tempCode2));
}
Activation2.append(Activation.mid(0,4));
Activation2.remove("00");
//激活码生成算法
//此处开始为激活码带有有效期信息的部分
QString str_yxq =tenToHexL(yxq+pwd[sj.mid(4,2).toInt()]).remove(0,1);
int jy = yxq ^ pwd[sj.mid(4,2).toInt()];
str_yxq.append(tenToHexL(jy).remove(0,1));
Activation2.append(str_yxq);
//有效期信息部分
return Activation2
}
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;
else
break;
}
//以mac地址为序号获取密码表相应值
QString machineCode;
for(int i=0;i<6;i++){
machineCode.append(text.mid(0,2));
text.remove(0,3);
}
return machineCode;
}
void Widget::on_pushButton_2_clicked()//激活按钮
{
QString code = ui->lineEdit->text();
QString tail = code.mid(code.length()-6,6);//code:QString激活码 tail:激活码后六位,包含有效期信息
//验证激活码有效性
QString machineCode = getMachineCode();
QString sj=QDate::currentDate.toString("yyMMdd");
QString Activation;
for(int j=0;j<6;j++)
{
int tempCode;
tempCode=pwd[machineCode.mid(j*2,2).toInt(nullptr,16)]<<sj.mid(j,1).toInt();
Activation.append(tenToHexL(tempCode));
}
QString Activation2;
for(int k=0;k<5;k++)
{
int tempCode2;
tempCode2=Activation.mid(4*k+4,4).toInt(nullptr,16)>>tenToBin(sj.mid(4,2).toInt()).mid(k,1).toInt();
Activation2.append(tenToHexL(tempCode2));
}
Activation2.append(Activation.mid(0,4));
Activation2.remove("00");
if(code.mid(0,code.length()-10)!=Activation2)
return ;//激活码无效,可以根据需求设定函数返回值,返回激活失败原因,我这里偷懒就直接在按钮里了
//验证有效期部分
QString tail = code.mid(code.length()-3,3);
int h = tail.toInt(nullptr,16);
int iyxq = h ^ pwd[sj.mid(4,2).toInt()];//逆解出有效期
QString str_yxq =tenToHexL(iyxq+pwd[sj.mid(4,2).toInt()]).remove(0,1);
if(str_yxq!=code.mid(code.length()-6,3))
return ;//激活码无效,有效期部分校验失败
//写注册文件
QFileInfo fileinfo("PassCode.dat");
if(!fileinfo.exists()){
QFile file("PassCode.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
QByteArray ba;
ba.resize(15);
for(int i=0;i<12;i++){
ba[i]=code.mid(2*i,2).toInt(nullptr,16);
}
ba[12]=tail.mid(0,2).toInt(nullptr,16);
ba[13]=tail.mid(2,2).toInt(nullptr,16);
ba[14]=tail.mid(4,2).toInt(nullptr,16);
out<<(QByteArray)ba;
out<<(QDate)QDate::currentDate();//date:QDate激活日期
file.flush();
file.close();
}
}
int Widget::checkHasActivate()
{
QFileInfo fileinfo("PassCode.dat");
if(!fileinfo.exists()){
return 0;//无注册文件,返回有效期0天,执行首次激活流程
}
else{
QFile file("PassCode.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
QByteArray ba;
QDate date;
QString code;
in >> ba;
in >> date;
for(int i=0;i<12;i++){
int a=ba[i];
code.append(tenToHexS(a));//tenToHexS()方法为十进制转为两个字符的十六进制
}
code.remove("00");
code.append(tenToHexS(ba[12]));
code.append(tenToHexS(ba[13]));
code.append(tenToHexS(ba[14]));
int yxq = checkActivationCode(code,date);//checkActivationCode为上述的验证激活码算法,返回有效期
if(yxq==3840)//永久
return 3840;
yxq = yxq-date.daysTo(QDate::currentDate());
if(yxq<=0||date.daysTo(QDate::currentDate())<0){
file.remove();//若有效期到期,或者检测到用户通过更改当前日期来延长有效期,则删除注册文件
//再次启动后需要执行首次激活
return 0;
}
return yxq;
}
}
int checkActivationCode(QString code, QDate date)
{
QString machineCode = getMachineCode();
QString sj=date.toString("yyMMdd");
QString Activation;
for(int j=0;j<6;j++)
{
int tempCode;
tempCode=pwd[machineCode.mid(j*2,2).toInt(nullptr,16)]<<sj.mid(j,1).toInt();
Activation.append(tenToHexL(tempCode));
}
QString Activation2;
for(int k=0;k<5;k++)
{
int tempCode2;
tempCode2=Activation.mid(4*k+4,4).toInt(nullptr,16)>>tenToBin(sj.mid(4,2).toInt()).mid(k,1).toInt();
Activation2.append(tenToHexL(tempCode2));
}
Activation2.append(Activation.mid(0,4));
Activation2.remove("00");
if(code.mid(0,code.length()-10)!=Activation2)
return 0;
QString tail = code.mid(code.length()-3,3);
int h = tail.toInt(nullptr,16);
int iyxq = h ^ pwd[sj.mid(4,2).toInt()];
QString str_yxq =tenToHexL(iyxq+pwd[sj.mid(4,2).toInt()]).remove(0,1);
if(str_yxq!=code.mid(code.length()-6,3))
return 0;
else
return iyxq;
}
QString Widget::tenToHexL(int ten)
{
QString a="0123456789ABCDEF";
QString res;
if(ten>255)
{
res=a.at(ten/4096);
res.append(a.at(ten/256%16));
res.append(a.at(ten/16%16));
res.append(a.at(ten%16));
}
else
{
res="00";
res.append(a.at(ten/16));
res.append(a.at(ten%16));
}
return res;
}
QString Widget::tenToHexS(int ten)
{
QString s = "0123456789ABCDEF";
QString res;
res.append(s.at(ten/16));
res.append(s.at(ten%16));
return res;
}
QString Widget::tenToBin(int ten)
{
QString res;
for(int i=0;i<5;i++)
{
res.prepend(QString::number(ten%2));
ten=ten/2;
}
return res;
}
源码下载