ccy
8 天以前 2830cce39c0f3e677993bb19c031eb61b43659a3
同步与CNNCSIM的加密解密的方式
5个文件已修改
6个文件已添加
1318 ■■■■ 已修改文件
LicenseAdministrator.pro 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aesni-key-exp.h 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
licensedata.cpp 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
licensedata.h 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mainwindow.cpp 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mainwindow.h 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mainwindow.ui 254 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
shortcrypto.cpp 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
shortcrypto.h 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tinyaes.cpp 264 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tinyaes.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LicenseAdministrator.pro
@@ -16,17 +16,23 @@
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
    licensedata.cpp \
    main.cpp \
    mainwindow.cpp \
    qaesencryption.cpp
    qaesencryption.cpp \
    shortcrypto.cpp \
    tinyaes.cpp
HEADERS += \
    aesni-enc-cbc.h \
    aesni-enc-ecb.h \
    aesni-key-exp.h \
    aesni-key-init.h \
    licensedata.h \
    mainwindow.h \
    qaesencryption.h
    qaesencryption.h \
    shortcrypto.h \
    tinyaes.h
FORMS += \
    mainwindow.ui
aesni-key-exp.h
@@ -10,9 +10,12 @@
bool check_aesni_support()
{
    unsigned int a,b,c,d;
    cpuid(1, a,b,c,d);
    return (c & 0x2000000);
//    unsigned int a,b,c,d;
//    cpuid(1, a,b,c,d);
//    return (c & 0x2000000);
    // 强制禁用 AES-NI,使用纯软件 AES 实现
    // 在 MSVC2017 + Qt 5.12.7 环境下,AES-NI 路径存在兼容性问题
    return false;
}
__m128i AES_128_ASSIST (__m128i temp1, __m128i temp2)
licensedata.cpp
New file
@@ -0,0 +1,166 @@
#include "licensedata.h"
#include <QDataStream>
#include <QtDebug>
LicenseData::LicenseData()
    : productId(0), verMajor(0), verMinor(0), activeState(0)
{
}
QByteArray LicenseData::toBinary() const
{
    QByteArray data;
    data.reserve(64);
    QDataStream stream(&data, QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian);
    // 1. 主板UUID:固定16字节
    QByteArray uuid = boardUuid.left(16);
    uuid.append(QByteArray(16 - uuid.size(), '\0'));
    stream.writeRawData(uuid.constData(), 16);
    // 2. CPU序列号:固定8字节
    QByteArray cpu = cpuSerial.left(8);
    cpu.append(QByteArray(8 - cpu.size(), '\0'));
    stream.writeRawData(cpu.constData(), 8);
    // 3. 用户名:长度前缀(1B) + UTF-8数据
    QByteArray userBytes = userName.toUtf8();
    if (userBytes.size() > 255) {
        userBytes = userBytes.left(255);
    }
    stream << static_cast<quint8>(userBytes.size());
    stream.writeRawData(userBytes.constData(), userBytes.size());
    // 4. 失效日期:2字节(距2000-01-01的天数)
    stream << dateToDays(expireDate);
    // 5. 产品号:1字节
    stream << productId;
    // 6. 版本号:主版本 + 次版本,各1字节
    stream << verMajor << verMinor;
    // 7. 激活状态:1字节
    stream << activeState;
    return data;
}
bool LicenseData::fromBinary(const QByteArray &data)
{
    if (data.size() < 30) {
        qWarning() << "LicenseData::fromBinary: data too short, need at least 30 bytes";
        return false;
    }
    QDataStream stream(data);
    stream.setByteOrder(QDataStream::BigEndian);
    // 1. UUID
    boardUuid.resize(16);
    stream.readRawData(boardUuid.data(), 16);
    // 2. CPU序列号
    cpuSerial.resize(8);
    stream.readRawData(cpuSerial.data(), 8);
    // 3. 用户名
    quint8 nameLen = 0;
    stream >> nameLen;
    if (data.size() < 25 + nameLen + 5) {
        qWarning() << "LicenseData::fromBinary: insufficient data for remaining fields";
        return false;
    }
    QByteArray userBytes(nameLen, '\0');
    stream.readRawData(userBytes.data(), nameLen);
    userName = QString::fromUtf8(userBytes);
    // 4. 日期
    quint16 days = 0;
    stream >> days;
    expireDate = daysToDate(days);
    // 5. 产品号
    stream >> productId;
    // 6. 版本
    stream >> verMajor >> verMinor;
    // 7. 激活状态
    stream >> activeState;
    return true;
}
QString LicenseData::toDebugString() const
{
    return QString("{UUID:%1, CPU:%2, User:%3, Expire:%4, Prod:%5, Ver:%6.%7, State:%8}")
        .arg(uuidBinaryToString(boardUuid))
        .arg(binaryToHexString(cpuSerial))
        .arg(userName)
        .arg(expireDate.toString("yyyy-MM-dd"))
        .arg(productId)
        .arg(verMajor).arg(verMinor)
        .arg(activeState);
}
quint16 LicenseData::dateToDays(const QDate &date) const
{
    QDate base(BASE_YEAR, BASE_MONTH, BASE_DAY);
    if (!date.isValid() || date < base) {
        return 0;
    }
    return static_cast<quint16>(base.daysTo(date));
}
QDate LicenseData::daysToDate(quint16 days) const
{
    QDate base(BASE_YEAR, BASE_MONTH, BASE_DAY);
    return base.addDays(days);
}
QByteArray LicenseData::uuidStringToBinary(const QString &uuidStr)
{
    QString clean = uuidStr;
    clean.remove('-');
    clean.remove('{');
    clean.remove('}');
    clean = clean.toUpper();
    if (clean.size() != 32) {
        return QByteArray();
    }
    return hexStringToBinary(clean);
}
QString LicenseData::uuidBinaryToString(const QByteArray &bin)
{
    if (bin.size() != 16) {
        return QString();
    }
    QString hex = binaryToHexString(bin);
    return QString("%1-%2-%3-%4-%5")
        .arg(hex.mid(0, 8))
        .arg(hex.mid(8, 4))
        .arg(hex.mid(12, 4))
        .arg(hex.mid(16, 4))
        .arg(hex.mid(20, 12));
}
QByteArray LicenseData::hexStringToBinary(const QString &hexStr)
{
    QString clean = hexStr;
    clean.remove(' ');
    QByteArray result;
    result.reserve(clean.size() / 2);
    for (int i = 0; i + 1 < clean.size(); i += 2) {
        bool ok;
        result.append(static_cast<char>(clean.mid(i, 2).toUInt(&ok, 16)));
    }
    return result;
}
QString LicenseData::binaryToHexString(const QByteArray &bin)
{
    return QString::fromLatin1(bin.toHex()).toUpper();
}
licensedata.h
New file
@@ -0,0 +1,57 @@
#ifndef LICENSEDATA_H
#define LICENSEDATA_H
#include <QByteArray>
#include <QString>
#include <QDate>
/**
 * @brief 许可证数据结构 V2(极致紧凑版)
 *
 * 二进制格式(大端序):
 *  [0..15]   16B  主板UUID(原始二进制)
 *  [16..23]   8B  CPU序列号(原始二进制)
 *  [24]       1B  用户名长度N
 *  [25..24+N] N B  用户名UTF-8数据
 *  [25+N..26+N] 2B  失效日期(距2000-01-01的天数,uint16)
 *  [27+N]     1B  产品号(uint8)
 *  [28+N]     1B  主版本号(uint8)
 *  [29+N]     1B  次版本号(uint8)
 *  [30+N]     1B  激活状态(uint8)
 *
 * 总长度 = 31 + N 字节
 */
struct LicenseData
{
    QByteArray boardUuid;    // 16字节二进制UUID
    QByteArray cpuSerial;    // 8字节二进制
    QString    userName;     // 用户名
    QDate      expireDate;   // 失效日期(仅日期,无时间)
    quint8     productId;    // 产品号
    quint8     verMajor;     // 主版本号
    quint8     verMinor;     // 次版本号
    quint8     activeState;  // 激活状态
    LicenseData();
    QByteArray toBinary() const;
    bool fromBinary(const QByteArray &data);
    QString toDebugString() const;
    // 辅助转换
    static QByteArray uuidStringToBinary(const QString &uuidStr);
    static QString    uuidBinaryToString(const QByteArray &bin);
    static QByteArray hexStringToBinary(const QString &hexStr);
    static QString    binaryToHexString(const QByteArray &bin);
private:
    // 日期基准:2000-01-01,用uint16存天数,范围 2000-01-01 ~ 2182-06-05
    static constexpr int BASE_YEAR = 2000;
    static constexpr int BASE_MONTH = 1;
    static constexpr int BASE_DAY = 1;
    quint16 dateToDays(const QDate &date) const;
    QDate daysToDate(quint16 days) const;
};
#endif // LICENSEDATA_H
mainwindow.cpp
@@ -1,6 +1,8 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qaesencryption.h"
#include "licensedata.h"
#include "shortcrypto.h"
#include <QClipboard>
#include <QDateTime>
@@ -48,6 +50,12 @@
    ui->label_biosnum->setVisible(false);
    ui->label_basenum_2->setVisible(false);
    ui->label_biosnum_2->setVisible(false);
    QTextOption opt = ui->textEdit_localid->document()->defaultTextOption();
    opt.setWrapMode(QTextOption::WrapAnywhere);
    ui->textEdit_localid->document()->setDefaultTextOption(opt);
    QTextOption opt_lic = ui->textEdit_licensekey->document()->defaultTextOption();
    opt_lic.setWrapMode(QTextOption::WrapAnywhere);
    ui->textEdit_licensekey->document()->setDefaultTextOption(opt_lic);
    //前七条是简化加密数据必用的,在这里设定好方便对应
    m_numToInfo.insert("1","Baseboard_Uuid");
    m_numToInfo.insert("2","CPU_Processorid");
@@ -269,57 +277,73 @@
void MainWindow::on_pushButton_decrypt_clicked()
{
    QString encryptlocalid = ui->textEdit_localid->toPlainText();
    QString localid = getDecrypt(encryptlocalid,key);
    QByteArray localidbyte = localid.toLocal8Bit();
    QJsonParseError err_rpt;
    QJsonDocument localidjsondoc(QJsonDocument::fromJson(localid.toUtf8(), &err_rpt));//字符串格式化为JSON
    if(err_rpt.error != QJsonParseError::NoError)
    {
        localinfo = LicenseInfo();
        licenseinfo = LicenseInfo();
        workingjsondoc = QJsonDocument();
        ui->textEdit_licensekey->setPlainText("");
        changeUIstate();
        qDebug() << QStringLiteral("localid JSON格式错误");
        QMessageBox msgbox(QMessageBox::Information,QStringLiteral(""),QStringLiteral("解析失败,不是一个正确的设备ID序列"),QMessageBox::Ok);
        msgbox.setButtonText(QMessageBox::Ok,QStringLiteral("确定"));
        msgbox.exec();
    }
    else    //JSON格式正确
    {
        QMessageBox msgbox(QMessageBox::Information,QStringLiteral(""),QStringLiteral("解析成功"),QMessageBox::Ok);
        msgbox.setButtonText(QMessageBox::Ok,QStringLiteral("确定"));
        msgbox.exec();
        ui->textEdit_licensekey->setPlainText(ui->textEdit_localid->toPlainText());
        workingjsondoc = QJsonDocument(QJsonDocument::fromJson(localidbyte));
        QJsonObject localid_Obj = localidjsondoc.object();
//        localinfo.Baseboard_Serialnumber = localid_Obj.value("Baseboard_Serialnumber").toString();
//        localinfo.Baseboard_Uuid = localid_Obj.value("Baseboard_Uuid").toString();
//        localinfo.Bios_Serialnumber = localid_Obj.value("Bios_Serialnumber").toString();
//        localinfo.CPU_Processorid = localid_Obj.value("CPU_Processorid").toString();
//        localinfo.Username = localid_Obj.value("Username").toString();
//        localinfo.IsEnabled_cell = localid_Obj.value("IsEnabled_cell").toInt();
//        localinfo.IsEnabled_aquifer = localid_Obj.value("IsEnabled_aquifer").toInt();
//        localinfo.IsEnabled_pipe = localid_Obj.value("IsEnabled_pipe").toInt();
//        localinfo.IsEnabled_network = localid_Obj.value("IsEnabled_network").toInt();
//        localinfo.LicensedDuration_end = localid_Obj.value("LicensedDuration_end").toString();
//        localinfo.LicensedDuration_start = localid_Obj.value("LicensedDuration_start").toString();
//        localinfo.Productid = localid_Obj.value("Productid").toString();
//        localinfo.Versionid = localid_Obj.value("Versionid").toString();
    // 一键解密
    lic2.fromBinary(ShortCrypto::decrypt(encryptlocalid, key));
    qDebug()<<"on_pushButton_decrypt_clicked"<<lic2.toDebugString();
        //与之前的加密对应,且去掉冗余信息
        localinfo.Baseboard_Uuid = localid_Obj.value(m_numToInfo.key("Baseboard_Uuid")).toString();
        localinfo.CPU_Processorid = localid_Obj.value(m_numToInfo.key("CPU_Processorid")).toString();
        localinfo.Username = localid_Obj.value(m_numToInfo.key("Username")).toString();
        localinfo.LicensedDuration_end = localid_Obj.value(m_numToInfo.key("LicensedDuration_end")).toString();
        localinfo.LicensedDuration_start = localid_Obj.value(m_numToInfo.key("LicensedDuration_start")).toString();
        localinfo.Productid = localid_Obj.value(m_numToInfo.key("Productid")).toString();
        localinfo.Versionid = localid_Obj.value(m_numToInfo.key("Versionid")).toString();
        localinfo.ActiveState = localid_Obj.value(m_numToInfo.key("ActiveState")).toInt();
    localinfo.Baseboard_Uuid = LicenseData::uuidBinaryToString(lic2.boardUuid);
    localinfo.CPU_Processorid = LicenseData::binaryToHexString(lic2.cpuSerial);
    localinfo.Username = lic2.userName;
    localinfo.LicensedDuration_end = lic2.expireDate.toString("yyyy-MM-dd");
//    localinfo.LicensedDuration_start = localid_Obj.value(m_numToInfo.key("LicensedDuration_start")).toString();
    localinfo.Productid = QString::number(lic2.productId);
    localinfo.Versionid = QString::number(lic2.verMajor)+"."+QString::number(lic2.verMinor);
    localinfo.ActiveState = static_cast<int>(lic2.activeState);
        licenseinfo = LicenseInfo(localinfo);
    ui->textEdit_licensekey->setPlainText(ui->textEdit_localid->toPlainText());
        changeUIstate();
    }
//    QString localid = getDecrypt(encryptlocalid,key);
//    QByteArray localidbyte = localid.toLocal8Bit();
//    QJsonParseError err_rpt;
//    QJsonDocument localidjsondoc(QJsonDocument::fromJson(localid.toUtf8(), &err_rpt));//字符串格式化为JSON
//    if(err_rpt.error != QJsonParseError::NoError)
//    {
//        localinfo = LicenseInfo();
//        licenseinfo = LicenseInfo();
//        workingjsondoc = QJsonDocument();
//        ui->textEdit_licensekey->setPlainText("");
//        changeUIstate();
//        qDebug() << QStringLiteral("localid JSON格式错误");
//        QMessageBox msgbox(QMessageBox::Information,QStringLiteral(""),QStringLiteral("解析失败,不是一个正确的设备ID序列"),QMessageBox::Ok);
//        msgbox.setButtonText(QMessageBox::Ok,QStringLiteral("确定"));
//        msgbox.exec();
//    }
//    else    //JSON格式正确
//    {
//        QMessageBox msgbox(QMessageBox::Information,QStringLiteral(""),QStringLiteral("解析成功"),QMessageBox::Ok);
//        msgbox.setButtonText(QMessageBox::Ok,QStringLiteral("确定"));
//        msgbox.exec();
//        ui->textEdit_licensekey->setPlainText(ui->textEdit_localid->toPlainText());
//        workingjsondoc = QJsonDocument(QJsonDocument::fromJson(localidbyte));
//        QJsonObject localid_Obj = localidjsondoc.object();
////        localinfo.Baseboard_Serialnumber = localid_Obj.value("Baseboard_Serialnumber").toString();
////        localinfo.Baseboard_Uuid = localid_Obj.value("Baseboard_Uuid").toString();
////        localinfo.Bios_Serialnumber = localid_Obj.value("Bios_Serialnumber").toString();
////        localinfo.CPU_Processorid = localid_Obj.value("CPU_Processorid").toString();
////        localinfo.Username = localid_Obj.value("Username").toString();
////        localinfo.IsEnabled_cell = localid_Obj.value("IsEnabled_cell").toInt();
////        localinfo.IsEnabled_aquifer = localid_Obj.value("IsEnabled_aquifer").toInt();
////        localinfo.IsEnabled_pipe = localid_Obj.value("IsEnabled_pipe").toInt();
////        localinfo.IsEnabled_network = localid_Obj.value("IsEnabled_network").toInt();
////        localinfo.LicensedDuration_end = localid_Obj.value("LicensedDuration_end").toString();
////        localinfo.LicensedDuration_start = localid_Obj.value("LicensedDuration_start").toString();
////        localinfo.Productid = localid_Obj.value("Productid").toString();
////        localinfo.Versionid = localid_Obj.value("Versionid").toString();
//        //与之前的加密对应,且去掉冗余信息
//        localinfo.Baseboard_Uuid = localid_Obj.value(m_numToInfo.key("Baseboard_Uuid")).toString();
//        localinfo.CPU_Processorid = localid_Obj.value(m_numToInfo.key("CPU_Processorid")).toString();
//        localinfo.Username = localid_Obj.value(m_numToInfo.key("Username")).toString();
//        localinfo.LicensedDuration_end = localid_Obj.value(m_numToInfo.key("LicensedDuration_end")).toString();
//        localinfo.LicensedDuration_start = localid_Obj.value(m_numToInfo.key("LicensedDuration_start")).toString();
//        localinfo.Productid = localid_Obj.value(m_numToInfo.key("Productid")).toString();
//        localinfo.Versionid = localid_Obj.value(m_numToInfo.key("Versionid")).toString();
//        localinfo.ActiveState = localid_Obj.value(m_numToInfo.key("ActiveState")).toInt();
//        licenseinfo = LicenseInfo(localinfo);
//        changeUIstate();
//    }
}
void MainWindow::on_pushButton_accreditall_clicked()
@@ -505,31 +529,25 @@
void MainWindow::giveLicense(int time)
{
    QJsonObject licensekey_Obj = workingjsondoc.object();
//    licensekey_Obj[m_numToInfo.key("IsEnabled_cell")] = 1;
//    licensekey_Obj[m_numToInfo.key("IsEnabled_aquifer")] = 1;
//    licensekey_Obj[m_numToInfo.key("IsEnabled_pipe")] = 1;
//    licensekey_Obj[m_numToInfo.key("IsEnabled_network")] = 1;
    licensekey_Obj[m_numToInfo.key("ActiveState")] = 1;
//    QDateTime licensedate = QDateTime::fromString(licensekey_Obj[m_numToInfo.key("LicensedDuration_end")].toString(),"yyyy-MM-dd hh:mm:ss");
//    if(licensedate.isNull()){
//        qDebug()<<"licenseTime is Null";
//        licensedate = QDateTime::currentDateTime();
//    }
    //现在点击授权是从当前的时间加授权时间
    QDateTime licensedate = QDateTime::currentDateTime();
    QDateTime newlicensedate = licensedate.addMonths(time);
    QString licensedatestr = newlicensedate.toString("yyyy-MM-dd hh:mm:ss");
    licensekey_Obj[m_numToInfo.key("LicensedDuration_start")] = licensedate.toString("yyyy-MM-dd hh:mm:ss");
    licensekey_Obj[m_numToInfo.key("LicensedDuration_end")] = licensedatestr;
    workingjsondoc.setObject(licensekey_Obj);
    //数据压缩,去空格换行等多余无用信息
    QByteArray compressedArray = QJsonDocument(licensekey_Obj).toJson(QJsonDocument::Compact);
    QByteArray jsonbytearray = qCompress(compressedArray,9);
    QString testid = jsonbytearray.toBase64();
    ui->textEdit_licensekey->setPlainText("");
    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(testid),key));
    setLicenseinfo(licensekey_Obj);
    QString licensedatestr = newlicensedate.toString("yyyy-MM-dd");
    lic2.expireDate = QDate::fromString(licensedatestr,"yyyy-MM-dd");
//    lic2.expireDate = lic2.expireDate.addMonths(time);
    lic2.activeState = 1;
    QString cipher = ShortCrypto::encrypt(lic2.toBinary(), key);
    ui->textEdit_licensekey->clear();
    ui->textEdit_licensekey->setPlainText(cipher);
    // 一键解密
    LicenseData lic3;
    lic3.fromBinary(ShortCrypto::decrypt(cipher, key));
    qDebug()<<"change"<<cipher<<lic3.toDebugString()<<cipher.size();
    //更新licenseinfo,只需要更新LicensedDuration_end、LicensedDuration_start、ActiveState
    licenseinfo.LicensedDuration_end = newlicensedate.toString("yyyy-MM-dd");
    licenseinfo.LicensedDuration_start = licensedate.toString("yyyy-MM-dd");
    licenseinfo.ActiveState = 1;
    changeUIstate();
    //将授权信息记录到excel表中
    QString edition ="";
    if(time == 3){
@@ -539,12 +557,12 @@
    }else if(time == 12){
        edition = QStringLiteral("专业版");
    }
    ActiveRecord(licensekey_Obj,edition,ui->textEdit_licensekey->toPlainText());
    ActiveRecord(lic2,edition,ui->textEdit_licensekey->toPlainText());
}
void MainWindow::ActiveRecord(QJsonObject jsonObj,QString edition, QString licenseKey)
void MainWindow::ActiveRecord(LicenseData lic,QString edition, QString licenseKey)
{
    QString Baseboard_Uuid = jsonObj[m_numToInfo.key("Baseboard_Uuid")].toString();
    QString Baseboard_Uuid = LicenseData::uuidBinaryToString(lic.boardUuid);
    QString src = QApplication::applicationDirPath();
    QDir dir(src);
    QString file_name(QStringLiteral("安全评价软件授权人数统计表.xlsx"));
@@ -587,24 +605,58 @@
        int rowCount = xlsx.dimension().rowCount()+1;
        int id = xlsx.read(rowCount-1,1).toInt();
        xlsx.write(rowCount, 1, id+1);
        xlsx.write(rowCount, 2, jsonObj[m_numToInfo.key("Baseboard_Uuid")].toString());
        xlsx.write(rowCount, 2, LicenseData::uuidBinaryToString(lic.boardUuid));
        xlsx.write(rowCount, 3, edition);
        xlsx.write(rowCount, 4, jsonObj[m_numToInfo.key("LicensedDuration_start")].toString());
        xlsx.write(rowCount, 5, jsonObj[m_numToInfo.key("LicensedDuration_end")].toString());
        xlsx.write(rowCount, 6, jsonObj[m_numToInfo.key("Productid")].toString());
        xlsx.write(rowCount, 7, jsonObj[m_numToInfo.key("Versionid")].toString());
        xlsx.write(rowCount, 4, QDate::currentDate().toString("yyyy-MM-dd"));
        xlsx.write(rowCount, 5, lic.expireDate.toString("yyyy-MM-dd"));
        xlsx.write(rowCount, 6, QString::number(lic2.productId));
        xlsx.write(rowCount, 7, QString::number(lic2.verMajor)+"."+QString::number(lic2.verMinor));
        xlsx.write(rowCount, 8, licenseKey);
    }else{
        //如果存在这条记录就更新数据信息
        xlsx.write(uuidColumn, 2, jsonObj[m_numToInfo.key("Baseboard_Uuid")].toString());
        xlsx.write(uuidColumn, 2, LicenseData::uuidBinaryToString(lic.boardUuid));
        xlsx.write(uuidColumn, 3, edition);
        xlsx.write(uuidColumn, 4, jsonObj[m_numToInfo.key("LicensedDuration_start")].toString());
        xlsx.write(uuidColumn, 5, jsonObj[m_numToInfo.key("LicensedDuration_end")].toString());
        xlsx.write(uuidColumn, 6, jsonObj[m_numToInfo.key("Productid")].toString());
        xlsx.write(uuidColumn, 7, jsonObj[m_numToInfo.key("Versionid")].toString());
        xlsx.write(uuidColumn, 4, QDate::currentDate().toString("yyyy-MM-dd"));
        xlsx.write(uuidColumn, 5, lic.expireDate.toString("yyyy-MM-dd"));
        xlsx.write(uuidColumn, 6, QString::number(lic2.productId));
        xlsx.write(uuidColumn, 7, QString::number(lic2.verMajor)+"."+QString::number(lic2.verMinor));
        xlsx.write(uuidColumn, 8, licenseKey);
    }
    xlsx.save();
}
QString MainWindow::getEncrypt_New()
{
    QString localid = "";
    LicenseInfo localinfo;
    //查询系统用户名
    localinfo.Username = qgetenv("USER"); // Linux系统
    if (localinfo.Username.isEmpty())
        localinfo.Username = qgetenv("USERNAME"); // Windows系统
    //查询CPU序列号
    localinfo.CPU_Processorid = getWindowsInfo("wmic cpu get processorid");
    //查询主板序列号
    localinfo.Baseboard_Serialnumber = getWindowsInfo("wmic baseboard get serialnumber");
    //查询BIOS序列号
    localinfo.Bios_Serialnumber = getWindowsInfo("wmic bios get serialnumber");
    //查询主板唯一标识
    localinfo.Baseboard_Uuid = getWindowsInfo("wmic csproduct get uuid");
    //尝试新的加密方法
    LicenseData lic;
    lic.boardUuid  = LicenseData::hexStringToBinary(localinfo.Baseboard_Uuid);
    lic.cpuSerial  = LicenseData::hexStringToBinary(localinfo.CPU_Processorid);
    lic.userName   = localinfo.Username;
    lic.expireDate = QDate::fromString(localinfo.LicensedDuration_end,"yyyy-MM-dd");
    lic.productId  = localinfo.Productid.toUInt();
    QString version = localinfo.Versionid;
    lic.verMajor   = version.split(".").at(0).toUInt();
    lic.verMinor   = version.split(".").at(1).toUInt();
    lic.activeState = localinfo.ActiveState;
    // 一键加密
    QString cipher = ShortCrypto::encrypt(lic.toBinary(), key);
//    ui->textEdit_localid->setText(cipher);
    return  cipher;
}
@@ -612,6 +664,9 @@
{
    QString localid = getLocalID();
    QString encryptid = getEncrypt(localid,key);
    //新的加密方法
    encryptid = getEncrypt_New();
    ui->textEdit_localid->setText(encryptid);
    localinfo = LicenseInfo();
@@ -725,38 +780,48 @@
void MainWindow::on_pushButton_setproid_clicked()
{
    QJsonObject licensekey_Obj = workingjsondoc.object();
    licensekey_Obj[m_numToInfo.key("Productid")] = ui->lineEdit_setproid->text();
    workingjsondoc.setObject(licensekey_Obj);
//    QJsonObject licensekey_Obj = workingjsondoc.object();
//    licensekey_Obj[m_numToInfo.key("Productid")] = ui->lineEdit_setproid->text();
//    workingjsondoc.setObject(licensekey_Obj);
    QByteArray compressedArray = QJsonDocument(licensekey_Obj).toJson(QJsonDocument::Compact);
    QByteArray jsonbytearray = qCompress(compressedArray,9);
    QString testid = jsonbytearray.toBase64();
    ui->textEdit_licensekey->setPlainText("");
    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(testid),key));
//    QByteArray jsonbytearray = workingjsondoc.toJson();
//    QByteArray compressedArray = QJsonDocument(licensekey_Obj).toJson(QJsonDocument::Compact);
//    QByteArray jsonbytearray = qCompress(compressedArray,9);
//    QString testid = jsonbytearray.toBase64();
//    ui->textEdit_licensekey->setPlainText("");
//    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(jsonbytearray),key));
    setLicenseinfo(licensekey_Obj);
//    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(testid),key));
    lic2.productId = ui->lineEdit_setproid->text().toUInt();
    QString cipher = ShortCrypto::encrypt(lic2.toBinary(), key);
    ui->textEdit_licensekey->setPlainText(cipher);
//    setLicenseinfo(licensekey_Obj);
    //這裡也只需要更新productId
    licenseinfo.Productid = ui->lineEdit_setproid->text();
    changeUIstate();
}
void MainWindow::on_pushButton_setversion_clicked()
{
    QJsonObject licensekey_Obj = workingjsondoc.object();
    licensekey_Obj[m_numToInfo.key("Versionid")] = ui->lineEdit_setversion->text();
    workingjsondoc.setObject(licensekey_Obj);
//    QJsonObject licensekey_Obj = workingjsondoc.object();
//    licensekey_Obj[m_numToInfo.key("Versionid")] = ui->lineEdit_setversion->text();
//    workingjsondoc.setObject(licensekey_Obj);
    QByteArray compressedArray = QJsonDocument(licensekey_Obj).toJson(QJsonDocument::Compact);
    QByteArray jsonbytearray = qCompress(compressedArray,9);
    QString testid = jsonbytearray.toBase64();
    ui->textEdit_licensekey->setPlainText("");
    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(testid),key));
//    QByteArray jsonbytearray = workingjsondoc.toJson();
//    QByteArray compressedArray = QJsonDocument(licensekey_Obj).toJson(QJsonDocument::Compact);
//    QByteArray jsonbytearray = qCompress(compressedArray,9);
//    QString testid = jsonbytearray.toBase64();
//    ui->textEdit_licensekey->setPlainText("");
//    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(jsonbytearray),key));
    setLicenseinfo(licensekey_Obj);
//    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(testid),key));
//    setLicenseinfo(licensekey_Obj);
    QString version = ui->lineEdit_setversion->text();
    lic2.verMajor = version.split(".").at(0).toUInt();
    lic2.verMinor = version.split(".").at(1).toUInt();
    QString cipher = ShortCrypto::encrypt(lic2.toBinary(), key);
    ui->textEdit_licensekey->setPlainText(cipher);
    //這裡也只需要更新Versionid
    licenseinfo.Versionid = ui->lineEdit_setversion->text();
    changeUIstate();
}
void MainWindow::on_pushButton_normal_clicked()
mainwindow.h
@@ -1,6 +1,8 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "licensedata.h"
#include <QMainWindow>
#include <QCryptographicHash>
#include <QJsonDocument>
@@ -22,10 +24,10 @@
    int IsEnabled_aquifer = 0;
    int IsEnabled_pipe = 0;
    int IsEnabled_network = 0;
    QString LicensedDuration_start = "2023-04-01 12:00:00";
    QString LicensedDuration_end = "2023-04-01 12:00:00";
    QString LicensedDuration_start = "2023-04-01";
    QString LicensedDuration_end = "2023-04-01";
    QString Productid = "1"; //产品号 (1,3)安全评价软件(2,3)数据库
    QString Versionid = "1.0.0.0"; //版本号 用于区分大版本,同一个大版本内可用
    QString Versionid = "2.0"; //版本号 用于区分大版本,同一个大版本内可用
} LicenseInfo;
class MainWindow : public QMainWindow
@@ -65,8 +67,10 @@
    //授权集中在一起,不同点在于时间
    void giveLicense(int time);
    void ActiveRecord(QJsonObject jsonObj,QString edition, QString licenseKey);
    void ActiveRecord(LicenseData lic,QString edition, QString licenseKey);
    //新的加密方法
    QString getEncrypt_New();
private slots:
    void on_pushButton_decrypt_clicked();
@@ -118,7 +122,11 @@
    QJsonDocument workingjsondoc;
    QString key = "9aFUEFjsqHsde4DOhirdskgdznSDHlfb0ae";
    LicenseData lic2;
    QByteArray key = "MySecretKey12345";
//    QString key = "9aFUEFjsqHsde4DOhirdskgdznSDHlfb0ae";
//    QByteArray key = "MySecretKey12345";  // 16字节密钥
    QMap<QString,QString> m_numToInfo;
};
mainwindow.ui
@@ -39,33 +39,6 @@
      <layout class="QGridLayout" name="gridLayout_3">
       <item row="0" column="0">
        <layout class="QGridLayout" name="gridLayout_2">
         <item row="0" column="1" rowspan="2" colspan="3">
          <widget class="QTextEdit" name="textEdit_licensekey">
           <property name="readOnly">
            <bool>true</bool>
           </property>
          </widget>
         </item>
         <item row="2" column="3">
          <widget class="QPushButton" name="pushButton_copykey">
           <property name="text">
            <string>复制密钥</string>
           </property>
          </widget>
         </item>
         <item row="1" column="0">
          <spacer name="verticalSpacer_2">
           <property name="orientation">
            <enum>Qt::Vertical</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>20</width>
             <height>40</height>
            </size>
           </property>
          </spacer>
         </item>
         <item row="2" column="1">
          <spacer name="horizontalSpacer_2">
           <property name="orientation">
@@ -86,10 +59,40 @@
           </property>
          </widget>
         </item>
         <item row="0" column="1" rowspan="2" colspan="3">
          <widget class="QTextEdit" name="textEdit_licensekey">
           <property name="lineWrapMode">
            <enum>QTextEdit::WidgetWidth</enum>
           </property>
           <property name="readOnly">
            <bool>true</bool>
           </property>
          </widget>
         </item>
         <item row="2" column="2">
          <widget class="QPushButton" name="pushButton_export">
           <property name="text">
            <string>导出文本</string>
           </property>
          </widget>
         </item>
         <item row="1" column="0">
          <spacer name="verticalSpacer_2">
           <property name="orientation">
            <enum>Qt::Vertical</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>20</width>
             <height>40</height>
            </size>
           </property>
          </spacer>
         </item>
         <item row="2" column="3">
          <widget class="QPushButton" name="pushButton_copykey">
           <property name="text">
            <string>复制密钥</string>
           </property>
          </widget>
         </item>
@@ -100,50 +103,13 @@
    </item>
    <item row="2" column="0">
     <layout class="QGridLayout" name="gridLayout_6">
      <item row="5" column="0">
       <widget class="QPushButton" name="pushButton_setproid">
      <item row="3" column="0">
       <widget class="QPushButton" name="pushButton_deaccreditall">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>设置产品号</string>
        </property>
       </widget>
      </item>
      <item row="3" column="1">
       <widget class="QPushButton" name="pushButton_accreditpipe">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>授权单裂隙</string>
        </property>
       </widget>
      </item>
      <item row="4" column="1">
       <widget class="QPushButton" name="pushButton_adddate">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>+1个月</string>
        </property>
       </widget>
      </item>
      <item row="1" column="0">
       <widget class="QPushButton" name="pushButton_normal">
        <property name="text">
         <string>授权普通版</string>
        </property>
       </widget>
      </item>
      <item row="2" column="0">
       <widget class="QPushButton" name="pushButton_accreditall">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>授权所有模块</string>
         <string>解除所有授权</string>
        </property>
       </widget>
      </item>
@@ -157,61 +123,13 @@
        </property>
       </widget>
      </item>
      <item row="2" column="2">
       <widget class="QPushButton" name="pushButton_accreditaquifer">
      <item row="4" column="1">
       <widget class="QPushButton" name="pushButton_adddate">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>授权含水通道</string>
        </property>
       </widget>
      </item>
      <item row="3" column="0">
       <widget class="QPushButton" name="pushButton_deaccreditall">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>解除所有授权</string>
        </property>
       </widget>
      </item>
      <item row="6" column="1" colspan="2">
       <widget class="QLineEdit" name="lineEdit_setversion">
        <property name="enabled">
         <bool>false</bool>
        </property>
       </widget>
      </item>
      <item row="5" column="1" colspan="2">
       <widget class="QLineEdit" name="lineEdit_setproid">
        <property name="enabled">
         <bool>false</bool>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QPushButton" name="pushButton_education">
        <property name="text">
         <string>授权教育版</string>
        </property>
       </widget>
      </item>
      <item row="0" column="2">
       <widget class="QPushButton" name="pushButton">
        <property name="text">
         <string>详细信息&gt;&gt;</string>
        </property>
       </widget>
      </item>
      <item row="6" column="0">
       <widget class="QPushButton" name="pushButton_setversion">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>设置版本</string>
         <string>+1个月</string>
        </property>
       </widget>
      </item>
@@ -222,13 +140,34 @@
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QPushButton" name="pushButton_accreditcell">
      <item row="1" column="0">
       <widget class="QPushButton" name="pushButton_normal">
        <property name="text">
         <string>授权普通版</string>
        </property>
       </widget>
      </item>
      <item row="5" column="1" colspan="2">
       <widget class="QLineEdit" name="lineEdit_setproid">
        <property name="enabled">
         <bool>false</bool>
        </property>
       </widget>
      </item>
      <item row="3" column="1">
       <widget class="QPushButton" name="pushButton_accreditpipe">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>授权孔隙单元</string>
         <string>授权单裂隙</string>
        </property>
       </widget>
      </item>
      <item row="6" column="1" colspan="2">
       <widget class="QLineEdit" name="lineEdit_setversion">
        <property name="enabled">
         <bool>false</bool>
        </property>
       </widget>
      </item>
@@ -242,13 +181,40 @@
        </property>
       </widget>
      </item>
      <item row="4" column="0">
       <widget class="QPushButton" name="pushButton_dateset">
      <item row="2" column="0">
       <widget class="QPushButton" name="pushButton_accreditall">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>时间同步</string>
         <string>授权所有模块</string>
        </property>
       </widget>
      </item>
      <item row="5" column="0">
       <widget class="QPushButton" name="pushButton_setproid">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>设置产品号</string>
        </property>
       </widget>
      </item>
      <item row="6" column="0">
       <widget class="QPushButton" name="pushButton_setversion">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>设置版本</string>
        </property>
       </widget>
      </item>
      <item row="0" column="2">
       <widget class="QPushButton" name="pushButton">
        <property name="text">
         <string>详细信息&gt;&gt;</string>
        </property>
       </widget>
      </item>
@@ -256,6 +222,43 @@
       <widget class="QPushButton" name="pushButton_viewUsers">
        <property name="text">
         <string>查看已激活用户</string>
        </property>
       </widget>
      </item>
      <item row="2" column="2">
       <widget class="QPushButton" name="pushButton_accreditaquifer">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>授权含水通道</string>
        </property>
       </widget>
      </item>
      <item row="2" column="1">
       <widget class="QPushButton" name="pushButton_accreditcell">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>授权孔隙单元</string>
        </property>
       </widget>
      </item>
      <item row="1" column="1">
       <widget class="QPushButton" name="pushButton_education">
        <property name="text">
         <string>授权教育版</string>
        </property>
       </widget>
      </item>
      <item row="4" column="0">
       <widget class="QPushButton" name="pushButton_dateset">
        <property name="enabled">
         <bool>false</bool>
        </property>
        <property name="text">
         <string>时间同步</string>
        </property>
       </widget>
      </item>
@@ -303,6 +306,9 @@
         </item>
         <item row="0" column="1" rowspan="2" colspan="6">
          <widget class="QTextEdit" name="textEdit_localid">
           <property name="lineWrapMode">
            <enum>QTextEdit::WidgetWidth</enum>
           </property>
           <property name="readOnly">
            <bool>false</bool>
           </property>
shortcrypto.cpp
New file
@@ -0,0 +1,200 @@
#include "shortcrypto.h"
#include "tinyaes.h"
#include <QtDebug>
// Base85 字符集:85个可打印字符,避开容易在URL/JSON里出问题的字符
const char *ShortCrypto::BASE85_CHARS =
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
namespace {
    QByteArray pkcs7Pad(const QByteArray &data, int blockSize) {
        int padLen = blockSize - (data.size() % blockSize);
        if (padLen == 0) padLen = blockSize;
        QByteArray result = data;
        result.append(QByteArray(padLen, static_cast<char>(padLen)));
        return result;
    }
    bool isPkcs7Valid(const QByteArray &data, int blockSize = 16) {
        if (data.isEmpty() || data.size() % blockSize != 0) return false;
        unsigned char padLen = static_cast<unsigned char>(data.at(data.size() - 1));
        if (padLen == 0 || padLen > static_cast<unsigned char>(blockSize)) return false;
        for (int i = 0; i < padLen; ++i)
            if (static_cast<unsigned char>(data.at(data.size() - 1 - i)) != padLen) return false;
        return true;
    }
    QByteArray pkcs7Unpad(const QByteArray &data) {
        if (data.isEmpty()) return QByteArray();
        unsigned char padLen = static_cast<unsigned char>(data.at(data.size() - 1));
        if (padLen == 0 || padLen > 16 || padLen > static_cast<unsigned char>(data.size())) return QByteArray();
        return data.left(data.size() - padLen);
    }
}
QString ShortCrypto::encrypt(const QByteArray &plaintext, const QByteArray &key, const QByteArray &iv)
{
    if (key.size() != 16) {
        qWarning() << "ShortCrypto::encrypt: key must be 16 bytes for AES-128";
        return QString();
    }
    QByteArray adjustedIv = iv;
    if (adjustedIv.isEmpty()) {
        adjustedIv = QByteArray(16, '\0');  // 默认全零IV(正式环境建议用随机IV并附带在密文前)
    } else if (adjustedIv.size() != 16) {
        adjustedIv = adjustedIv.left(16);
        adjustedIv.append(QByteArray(16 - adjustedIv.size(), '\0'));
    }
    // 1. PKCS7 填充
    QByteArray padded = pkcs7Pad(plaintext, 16);
    // 2. AES-128-CBC 加密(使用 Tiny-AES-C,纯软件实现,无 MSVC 兼容性问题)
    QByteArray encrypted = padded;
    struct AES_ctx ctx;
    AES_init_ctx_iv(&ctx, reinterpret_cast<const uint8_t*>(key.constData()),
                    reinterpret_cast<const uint8_t*>(adjustedIv.constData()));
    AES_CBC_encrypt_buffer(&ctx, reinterpret_cast<uint8_t*>(encrypted.data()), encrypted.size());
    // 3. Base85 编码,缩短字符数
    QByteArray encoded = base85Encode(encrypted);
    return QString::fromLatin1(encoded);
}
QByteArray ShortCrypto::decrypt(const QString &ciphertext, const QByteArray &key, const QByteArray &iv)
{
    if (key.size() != 16) {
        qWarning() << "ShortCrypto::decrypt: key must be 16 bytes for AES-128";
        return QByteArray();
    }
    QByteArray adjustedIv = iv;
    if (adjustedIv.isEmpty()) {
        adjustedIv = QByteArray(16, '\0');
    } else if (adjustedIv.size() != 16) {
        adjustedIv = adjustedIv.left(16);
        adjustedIv.append(QByteArray(16 - adjustedIv.size(), '\0'));
    }
    // 1. Base85 解码
    QByteArray encrypted = base85Decode(ciphertext);
    if (encrypted.isEmpty()) {
        qWarning() << "ShortCrypto::decrypt: base85 decode failed";
        return QByteArray();
    }
    if (encrypted.size() % 16 != 0) {
        qWarning() << "ShortCrypto::decrypt: decoded data size not aligned to block size:" << encrypted.size();
        return QByteArray();
    }
    // 2. AES-128-CBC 解密
    QByteArray decrypted = encrypted;
    struct AES_ctx ctx;
    AES_init_ctx_iv(&ctx, reinterpret_cast<const uint8_t*>(key.constData()),
                    reinterpret_cast<const uint8_t*>(adjustedIv.constData()));
    AES_CBC_decrypt_buffer(&ctx, reinterpret_cast<uint8_t*>(decrypted.data()), decrypted.size());
    // 3. PKCS7 验证和移除填充
    if (!isPkcs7Valid(decrypted)) {
        qWarning() << "ShortCrypto::decrypt: PKCS7 validation failed, wrong key or corrupted data";
        return QByteArray();
    }
    return pkcs7Unpad(decrypted);
}
QByteArray ShortCrypto::base85Encode(const QByteArray &data)
{
    QByteArray result;
    result.reserve((data.size() + 3) / 4 * 5);
    const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data.constData());
    int len = data.size();
    while (len >= 4) {
        quint32 val = (quint32(ptr[0]) << 24) | (quint32(ptr[1]) << 16) |
                      (quint32(ptr[2]) << 8) | quint32(ptr[3]);
        char buf[5];
        for (int i = 4; i >= 0; --i) {
            buf[i] = BASE85_CHARS[val % 85];
            val /= 85;
        }
        result.append(buf, 5);
        ptr += 4;
        len -= 4;
    }
    // 处理剩余字节(1~3字节)
    if (len > 0) {
        quint32 val = 0;
        for (int i = 0; i < len; ++i) {
            val |= (quint32(ptr[i]) << (24 - i * 8));
        }
        char buf[5];
        for (int i = 4; i >= 0; --i) {
            buf[i] = BASE85_CHARS[val % 85];
            val /= 85;
        }
        result.append(buf, len + 1);  // n字节需要n+1个字符表示
    }
    return result;
}
QByteArray ShortCrypto::base85Decode(const QString &text)
{
    QByteArray input = text.toLatin1();
    QByteArray result;
    result.reserve(input.size() / 5 * 4);
    // 构建反向查找表
    int charToVal[256];
    memset(charToVal, -1, sizeof(charToVal));
    for (int i = 0; i < 85; ++i) {
        charToVal[static_cast<unsigned char>(BASE85_CHARS[i])] = i;
    }
    const unsigned char *ptr = reinterpret_cast<const unsigned char *>(input.constData());
    int len = input.size();
    int pos = 0;
    while (pos < len) {
        // 读取一个5字符块(或末尾的短块)
        int chunkLen = qMin(5, len - pos);
        quint32 val = 0;
        for (int i = 0; i < chunkLen; ++i) {
            int v = charToVal[ptr[pos + i]];
            if (v < 0) {
                qWarning() << "ShortCrypto::base85Decode: invalid character:" << QChar(ptr[pos + i]);
                return QByteArray();
            }
            val = val * 85 + v;
        }
        if (chunkLen == 5) {
            result.append(static_cast<char>((val >> 24) & 0xFF));
            result.append(static_cast<char>((val >> 16) & 0xFF));
            result.append(static_cast<char>((val >> 8) & 0xFF));
            result.append(static_cast<char>(val & 0xFF));
        } else {
            // 末尾短块:用 'u'(84) 填充到 5 个字符,再解码
            for (int i = chunkLen; i < 5; ++i)
                val = val * 85 + 84;
            char out[4];
            out[0] = static_cast<char>((val >> 24) & 0xFF);
            out[1] = static_cast<char>((val >> 16) & 0xFF);
            out[2] = static_cast<char>((val >> 8) & 0xFF);
            out[3] = static_cast<char>(val & 0xFF);
            int outBytes = chunkLen - 1;
            for (int i = 0; i < outBytes; ++i)
                result.append(out[i]);
        }
        pos += chunkLen;
    }
    return result;
}
shortcrypto.h
New file
@@ -0,0 +1,40 @@
#ifndef SHORTCRYPTO_H
#define SHORTCRYPTO_H
#include <QByteArray>
#include <QString>
/**
 * @brief 最短密文加密工具类
 * 流程:明文 → PKCS7填充 → AES-128-CBC加密 → Base85编码
 */
class ShortCrypto
{
public:
    /**
     * @brief 加密
     * @param plaintext 原始明文
     * @param key 16字节密钥(AES-128)
     * @param iv 16字节初始向量,可为空(内部自动补零)
     * @return Base85编码的密文字符串
     */
    static QString encrypt(const QByteArray &plaintext, const QByteArray &key, const QByteArray &iv = QByteArray());
    /**
     * @brief 解密
     * @param ciphertext Base85编码的密文
     * @param key 16字节密钥(AES-128)
     * @param iv 16字节初始向量,必须与加密时一致
     * @return 原始明文
     */
    static QByteArray decrypt(const QString &ciphertext, const QByteArray &key, const QByteArray &iv = QByteArray());
private:
    // Base85 字符集(RFC 1924 变体,不含引号/逗号/句点/斜杠,避免JSON/XML转义问题)
    static const char *BASE85_CHARS;
    static QByteArray base85Encode(const QByteArray &data);
    static QByteArray base85Decode(const QString &text);
};
#endif // SHORTCRYPTO_H
tinyaes.cpp
New file
@@ -0,0 +1,264 @@
#include "tinyaes.h"
#include <string.h>
#define Nb 4
#define Nk 4
#define Nr 10
typedef uint8_t state_t[4][4];
static const uint8_t sbox[256] = {
    0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
    0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
    0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
    0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
    0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
    0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
    0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
    0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
    0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
    0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
    0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
    0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
    0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
    0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
    0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
    0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16
};
static const uint8_t rsbox[256] = {
    0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
    0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
    0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
    0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
    0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
    0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
    0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
    0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
    0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
    0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
    0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
    0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
    0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
    0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
    0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
    0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
};
static const uint8_t Rcon[11] = {
    0x8d,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36
};
#define getSBoxValue(num) (sbox[(num)])
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{
    unsigned i, j, k;
    uint8_t tempa[4];
    for (i = 0; i < Nk; ++i) {
        RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
        RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
        RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
        RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
    }
    for (i = Nk; i < Nb * (Nr + 1); ++i) {
        k = (i - 1) * 4;
        tempa[0]=RoundKey[k + 0];
        tempa[1]=RoundKey[k + 1];
        tempa[2]=RoundKey[k + 2];
        tempa[3]=RoundKey[k + 3];
        if (i % Nk == 0) {
            const uint8_t u8tmp = tempa[0];
            tempa[0] = tempa[1];
            tempa[1] = tempa[2];
            tempa[2] = tempa[3];
            tempa[3] = u8tmp;
            tempa[0] = getSBoxValue(tempa[0]);
            tempa[1] = getSBoxValue(tempa[1]);
            tempa[2] = getSBoxValue(tempa[2]);
            tempa[3] = getSBoxValue(tempa[3]);
            tempa[0] = tempa[0] ^ Rcon[i/Nk];
        }
        j = i * 4; k=(i - Nk) * 4;
        RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
        RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
        RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
        RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
    }
}
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
{
    KeyExpansion(ctx->RoundKey, key);
    memcpy(ctx->Iv, iv, AES_BLOCKLEN);
}
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
{
    uint8_t i,j;
    for (i = 0; i < 4; ++i)
        for (j = 0; j < 4; ++j)
            (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
}
static void SubBytes(state_t* state)
{
    uint8_t i, j;
    for (i = 0; i < 4; ++i)
        for (j = 0; j < 4; ++j)
            (*state)[j][i] = getSBoxValue((*state)[j][i]);
}
static void ShiftRows(state_t* state)
{
    uint8_t temp;
    temp           = (*state)[0][1];
    (*state)[0][1] = (*state)[1][1];
    (*state)[1][1] = (*state)[2][1];
    (*state)[2][1] = (*state)[3][1];
    (*state)[3][1] = temp;
    temp           = (*state)[0][2];
    (*state)[0][2] = (*state)[2][2];
    (*state)[2][2] = temp;
    temp           = (*state)[1][2];
    (*state)[1][2] = (*state)[3][2];
    (*state)[3][2] = temp;
    temp           = (*state)[0][3];
    (*state)[0][3] = (*state)[3][3];
    (*state)[3][3] = (*state)[2][3];
    (*state)[2][3] = (*state)[1][3];
    (*state)[1][3] = temp;
}
static uint8_t xtime(uint8_t x)
{
    return ((x<<1) ^ (((x>>7) & 1) * 0x1b));
}
static void MixColumns(state_t* state)
{
    uint8_t i;
    uint8_t Tmp, Tm, t;
    for (i = 0; i < 4; ++i) {
        t   = (*state)[i][0];
        Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
        Tm  = (*state)[i][0] ^ (*state)[i][1]; Tm = xtime(Tm);  (*state)[i][0] ^= Tm ^ Tmp;
        Tm  = (*state)[i][1] ^ (*state)[i][2]; Tm = xtime(Tm);  (*state)[i][1] ^= Tm ^ Tmp;
        Tm  = (*state)[i][2] ^ (*state)[i][3]; Tm = xtime(Tm);  (*state)[i][2] ^= Tm ^ Tmp;
        Tm  = (*state)[i][3] ^ t;              Tm = xtime(Tm);  (*state)[i][3] ^= Tm ^ Tmp;
    }
}
static uint8_t Multiply(uint8_t x, uint8_t y)
{
    return (((y & 1) * x) ^
           ((y>>1 & 1) * xtime(x)) ^
           ((y>>2 & 1) * xtime(xtime(x))) ^
           ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
           ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))));
}
static void InvMixColumns(state_t* state)
{
    int i;
    uint8_t a, b, c, d;
    for (i = 0; i < 4; ++i) {
        a = (*state)[i][0];
        b = (*state)[i][1];
        c = (*state)[i][2];
        d = (*state)[i][3];
        (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
        (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
        (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
        (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
    }
}
static void InvSubBytes(state_t* state)
{
    uint8_t i, j;
    for (i = 0; i < 4; ++i)
        for (j = 0; j < 4; ++j)
            (*state)[j][i] = rsbox[(*state)[j][i]];
}
static void InvShiftRows(state_t* state)
{
    uint8_t temp;
    temp = (*state)[3][1];
    (*state)[3][1] = (*state)[2][1];
    (*state)[2][1] = (*state)[1][1];
    (*state)[1][1] = (*state)[0][1];
    (*state)[0][1] = temp;
    temp = (*state)[0][2];
    (*state)[0][2] = (*state)[2][2];
    (*state)[2][2] = temp;
    temp = (*state)[1][2];
    (*state)[1][2] = (*state)[3][2];
    (*state)[3][2] = temp;
    temp = (*state)[0][3];
    (*state)[0][3] = (*state)[1][3];
    (*state)[1][3] = (*state)[2][3];
    (*state)[2][3] = (*state)[3][3];
    (*state)[3][3] = temp;
}
static void Cipher(state_t* state, const uint8_t* RoundKey)
{
    uint8_t round = 0;
    AddRoundKey(0, state, RoundKey);
    for (round = 1; ; ++round) {
        SubBytes(state);
        ShiftRows(state);
        if (round == Nr) break;
        MixColumns(state);
        AddRoundKey(round, state, RoundKey);
    }
    AddRoundKey(Nr, state, RoundKey);
}
static void InvCipher(state_t* state, const uint8_t* RoundKey)
{
    uint8_t round = 0;
    AddRoundKey(Nr, state, RoundKey);
    for (round = (Nr - 1); ; --round) {
        InvShiftRows(state);
        InvSubBytes(state);
        AddRoundKey(round, state, RoundKey);
        if (round == 0) break;
        InvMixColumns(state);
    }
}
static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
{
    uint8_t i;
    for (i = 0; i < AES_BLOCKLEN; ++i)
        buf[i] ^= Iv[i];
}
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{
    size_t i;
    uint8_t* Iv = ctx->Iv;
    for (i = 0; i < length; i += AES_BLOCKLEN) {
        XorWithIv(buf, Iv);
        Cipher((state_t*)buf, ctx->RoundKey);
        Iv = buf;
        buf += AES_BLOCKLEN;
    }
    memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length)
{
    size_t i;
    uint8_t storeNextIv[AES_BLOCKLEN];
    for (i = 0; i < length; i += AES_BLOCKLEN) {
        memcpy(storeNextIv, buf, AES_BLOCKLEN);
        InvCipher((state_t*)buf, ctx->RoundKey);
        XorWithIv(buf, ctx->Iv);
        memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
        buf += AES_BLOCKLEN;
    }
}
tinyaes.h
New file
@@ -0,0 +1,21 @@
#ifndef TINYAES_H
#define TINYAES_H
#include <stdint.h>
#include <stddef.h>
#define AES_BLOCKLEN 16
#define AES_KEYLEN 16
#define AES_keyExpSize 176
struct AES_ctx
{
    uint8_t RoundKey[AES_keyExpSize];
    uint8_t Iv[AES_BLOCKLEN];
};
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
#endif // TINYAES_H