From 5e1e4a4b57e298806dba97175fa1fbd5c771c7cd Mon Sep 17 00:00:00 2001
From: ccy <3140717620@qq.com>
Date: 星期五, 09 十月 2026 16:17:18 +0800
Subject: [PATCH] 新的加密方式

---
 licensedata.h   |   25 ++++
 mainwindow.cpp  |   18 +-
 shortcrypto.cpp |  129 +++++++++++++++++++++
 shortcrypto.h   |   25 ++++
 licensedata.cpp |  112 ++++++++++++++++++
 5 files changed, 302 insertions(+), 7 deletions(-)

diff --git a/licensedata.cpp b/licensedata.cpp
index 26d5d1b..fa31615 100644
--- a/licensedata.cpp
+++ b/licensedata.cpp
@@ -1,5 +1,7 @@
 锘�#include "licensedata.h"
 #include <QDataStream>
+#include <QCryptographicHash>
+#include <QRandomGenerator>
 #include <QtDebug>
 
 LicenseData::LicenseData()
@@ -105,6 +107,116 @@
         .arg(activeState);
 }
 
+// ===== V3 绱у噾鏍煎紡锛�20浣嶈鍙瘑閽ョ敤锛�=====
+
+QByteArray LicenseData::machineFingerprint(const QByteArray &uuid, const QByteArray &cpu, const QByteArray &key)
+{
+    // 涓巘oBinary鐩稿悓鐨勫畾闀胯鏁达紝淇濊瘉鎺堟潈绔拰楠岃瘉绔鍚屼竴鍙版満鍣ㄧ畻鍑哄悓涓�鎸囩汗
+    QByteArray u = uuid.left(16);
+    u.append(QByteArray(16 - u.size(), '\0'));
+    QByteArray c = cpu.left(8);
+    c.append(QByteArray(8 - c.size(), '\0'));
+
+    QCryptographicHash hash(QCryptographicHash::Sha256);
+    hash.addData(key);
+    hash.addData(u);
+    hash.addData(c);
+    return hash.result().left(8);
+}
+
+quint16 LicenseData::crc16(const QByteArray &data)
+{
+    // CRC16-CCITT (0xFFFF 鍒濆�硷紝0x1021 澶氶」寮�)
+    quint16 crc = 0xFFFF;
+    for (int i = 0; i < data.size(); ++i) {
+        crc ^= static_cast<quint16>(static_cast<unsigned char>(data.at(i))) << 8;
+        for (int b = 0; b < 8; ++b) {
+            crc = (crc & 0x8000) ? static_cast<quint16>((crc << 1) ^ 0x1021)
+                                 : static_cast<quint16>(crc << 1);
+        }
+    }
+    return crc;
+}
+
+QByteArray LicenseData::toBinaryV3(const QByteArray &key) const
+{
+    QByteArray data(16, '\0');
+
+    // [0..7] 鏈哄櫒鎸囩汗
+    QByteArray fp = machineFingerprint(boardUuid, cpuSerial, key);
+    memcpy(data.data(), fp.constData(), 8);
+
+    // [8..9] 澶辨晥鏃ユ湡锛堜笌V2鍚屼竴2000-01-01鍩哄噯锛�
+    quint16 days = dateToDays(expireDate);
+    data[8]  = static_cast<char>((days >> 8) & 0xFF);
+    data[9]  = static_cast<char>(days & 0xFF);
+
+    // [10] 浜у搧鍙�
+    data[10] = static_cast<char>(productId);
+
+    // [11] 鐗堟湰锛氶珮4浣嶄富鐗堟湰 | 浣�4浣嶆鐗堟湰
+    data[11] = static_cast<char>(((verMajor & 0x0F) << 4) | (verMinor & 0x0F));
+
+    // [12] 鏍囧織锛氶珮4浣嶆牸寮忕増鏈�(1)锛屼綆4浣嶆縺娲荤姸鎬�
+    data[12] = static_cast<char>(0x10 | (activeState & 0x0F));
+
+    // [13..14] CRC16锛堣鐩朳0..12]锛岄殢鏈虹洂涓嶅弬涓庯級
+    quint16 crc = crc16(data.left(13));
+    data[13] = static_cast<char>((crc >> 8) & 0xFF);
+    data[14] = static_cast<char>(crc & 0xFF);
+
+    // [15] 闅忔満鐩�
+    data[15] = static_cast<char>(QRandomGenerator::global()->generate() & 0xFF);
+
+    return data;
+}
+
+bool LicenseData::fromBinaryV3(const QByteArray &data)
+{
+    if (data.size() != 16) {
+        return false;
+    }
+
+    quint8 flags = static_cast<quint8>(data.at(12));
+    if ((flags >> 4) != 0x01) {
+        qWarning() << "LicenseData::fromBinaryV3: not a V3 payload, format version ="
+                   << (flags >> 4);
+        return false;
+    }
+
+    quint16 expectCrc = static_cast<quint16>((static_cast<quint8>(data.at(13)) << 8)
+                                             | static_cast<quint8>(data.at(14)));
+    if (crc16(data.left(13)) != expectCrc) {
+        qWarning() << "LicenseData::fromBinaryV3: CRC check failed, wrong key or corrupted data";
+        return false;
+    }
+
+    machineFp = data.left(8);
+
+    quint16 days = static_cast<quint16>((static_cast<quint8>(data.at(8)) << 8)
+                                        | static_cast<quint8>(data.at(9)));
+    expireDate = daysToDate(days);
+
+    productId = static_cast<quint8>(data.at(10));
+
+    quint8 ver = static_cast<quint8>(data.at(11));
+    verMajor = ver >> 4;
+    verMinor = ver & 0x0F;
+
+    activeState = flags & 0x0F;
+    return true;
+}
+
+QString LicenseData::toDebugStringV3() const
+{
+    return QString("{FP:%1, Expire:%2, Prod:%3, Ver:%4.%5, State:%6}")
+        .arg(binaryToHexString(machineFp))
+        .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);
diff --git a/licensedata.h b/licensedata.h
index e732d3d..d964f09 100644
--- a/licensedata.h
+++ b/licensedata.h
@@ -38,6 +38,31 @@
     bool fromBinary(const QByteArray &data);
     QString toDebugString() const;
 
+    /**
+     * @brief V3 绱у噾鏍煎紡锛�28浣嶇函澶у啓璁稿彲瀵嗛挜鐢紝鎭板ソ16瀛楄妭锛�
+     *
+     * 浜岃繘鍒跺竷灞�锛堝ぇ绔簭锛夛細
+     *  [0..7]    8B  鏈哄櫒鎸囩汗 = SHA256(瀵嗛挜鈥朥UID(16B)鈥朇PU(8B)) 鎴柇鍓�8瀛楄妭
+     *  [8..9]    2B  澶辨晥鏃ユ湡锛堣窛2000-01-01鐨勫ぉ鏁帮紝uint16锛屼笌V2鍚屽熀鍑嗭級
+     *  [10]      1B  浜у搧鍙�
+     *  [11]      1B  鐗堟湰鍙凤紙楂�4浣嶄富鐗堟湰 | 浣�4浣嶆鐗堟湰锛�
+     *  [12]      1B  鏍囧織锛堥珮4浣嶆牸寮忕増鏈�=1锛屼綆4浣嶆縺娲荤姸鎬侊級
+     *  [13..14]  2B  CRC16-CCITT锛堣鐩朳0..12]锛�
+     *  [15]      1B  闅忔満鐩愶紙閬垮厤鍚屾満鍚屾棩鏈熷瘑鏂囧畬鍏ㄧ浉鍚岋級
+     *
+     * 涓嶸2鐨勫尯鍒細UUID/CPU涓嶅啀鏄庢枃闅忓瘑閽ユ惡甯︼紝鍙甫涓嶅彲閫嗘寚绾癸紱
+     * 璁惧ID浠嶇敤V2鏍煎紡锛堥渶瑕佽繕鍘熸満鍣ㄤ俊鎭級锛屼粎璁稿彲瀵嗛挜鐢╒3銆�
+     */
+    QByteArray toBinaryV3(const QByteArray &key) const;
+    bool fromBinaryV3(const QByteArray &data);
+    QString toDebugStringV3() const;
+
+    QByteArray machineFp;    // V3瑙e嚭鐨勬満鍣ㄦ寚绾癸紙8瀛楄妭锛夛紱V2涓负绌�
+
+    // 鏈哄櫒鎸囩汗锛氭巿鏉冪涓庨獙璇佺蹇呴』鐢ㄥ悓涓�绠楁硶銆佸悓涓�瀵嗛挜
+    static QByteArray machineFingerprint(const QByteArray &uuid, const QByteArray &cpu, const QByteArray &key);
+    static quint16 crc16(const QByteArray &data);
+
     // 杈呭姪杞崲
     static QByteArray uuidStringToBinary(const QString &uuidStr);
     static QString    uuidBinaryToString(const QByteArray &bin);
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 1292e42..93e1d2d 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -279,7 +279,6 @@
     QString encryptlocalid = ui->textEdit_localid->toPlainText();
     // 涓�閿В瀵�
     lic2.fromBinary(ShortCrypto::decrypt(encryptlocalid, key));
-    qDebug()<<"on_pushButton_decrypt_clicked"<<lic2.toDebugString();
     //涓庝箣鍓嶇殑鍔犲瘑瀵瑰簲,涓斿幓鎺夊啑浣欎俊鎭�
     localinfo.Baseboard_Uuid = LicenseData::uuidBinaryToString(lic2.boardUuid);
     localinfo.CPU_Processorid = LicenseData::binaryToHexString(lic2.cpuSerial);
@@ -536,13 +535,18 @@
     lic2.expireDate = QDate::fromString(licensedatestr,"yyyy-MM-dd");
 //    lic2.expireDate = lic2.expireDate.addMonths(time);
     lic2.activeState = 1;
-    QString cipher = ShortCrypto::encrypt(lic2.toBinary(), key);
+    // V3绱у噾鏍煎紡锛�28浣嶇函澶у啓锛夛細鏈哄櫒淇℃伅浠ユ寚绾瑰舰寮忕粦瀹�
+    QString cipher = ShortCrypto::encryptRaw(lic2.toBinaryV3(key), 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();
+    if (lic3.fromBinaryV3(ShortCrypto::decryptRaw(cipher, key))) {
+        qDebug() << "V3鑷閫氳繃:" << lic3.toDebugStringV3();
+    } else {
+        qWarning() << "V3鑷澶辫触";
+    }
+
     //鏇存柊licenseinfo锛屽彧闇�瑕佹洿鏂癓icensedDuration_end銆丩icensedDuration_start銆丄ctiveState
     licenseinfo.LicensedDuration_end = newlicensedate.toString("yyyy-MM-dd");
     licenseinfo.LicensedDuration_start = licensedate.toString("yyyy-MM-dd");
@@ -791,7 +795,7 @@
 //    ui->textEdit_licensekey->setPlainText(getEncrypt(QString(testid),key));
 
     lic2.productId = ui->lineEdit_setproid->text().toUInt();
-    QString cipher = ShortCrypto::encrypt(lic2.toBinary(), key);
+    QString cipher = ShortCrypto::encryptRaw(lic2.toBinaryV3(key), key);
     ui->textEdit_licensekey->setPlainText(cipher);
 //    setLicenseinfo(licensekey_Obj);
 
@@ -817,7 +821,7 @@
     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);
+    QString cipher = ShortCrypto::encryptRaw(lic2.toBinaryV3(key), key);
     ui->textEdit_licensekey->setPlainText(cipher);
     //閫欒!涔熷彧闇�瑕佹洿鏂癡ersionid
     licenseinfo.Versionid = ui->lineEdit_setversion->text();
diff --git a/shortcrypto.cpp b/shortcrypto.cpp
index 796fcb8..e6d80fd 100644
--- a/shortcrypto.cpp
+++ b/shortcrypto.cpp
@@ -1,10 +1,16 @@
 锘�#include "shortcrypto.h"
 #include "tinyaes.h"
 #include <QtDebug>
+#include <QtMath>
+#include <algorithm>
 
 // Base85 瀛楃闆嗭細85涓彲鎵撳嵃瀛楃锛岄伩寮�瀹规槗鍦║RL/JSON閲屽嚭闂鐨勫瓧绗�
 const char *ShortCrypto::BASE85_CHARS =
     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
+
+// V3 瀛楃闆嗭細绾ぇ鍐欏瓧姣嶏紙26瀛楃锛夛紝璁稿彲瀵嗛挜鍙惈 A-Z锛�28浣�
+const char *ShortCrypto::V3_CHARS =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
 namespace {
     QByteArray pkcs7Pad(const QByteArray &data, int blockSize) {
@@ -105,6 +111,129 @@
     return pkcs7Unpad(decrypted);
 }
 
+QString ShortCrypto::encryptRaw(const QByteArray &plaintext, const QByteArray &key)
+{
+    if (key.size() != 16) {
+        qWarning() << "ShortCrypto::encryptRaw: key must be 16 bytes for AES-128";
+        return QString();
+    }
+    if (plaintext.isEmpty() || plaintext.size() % 16 != 0) {
+        qWarning() << "ShortCrypto::encryptRaw: plaintext size must be a non-zero multiple of 16, got"
+                   << plaintext.size();
+        return QString();
+    }
+
+    // 鍗曞潡鏃跺叏闆禝V鐨凜BC绛変环浜嶦CB锛涘鍧楁椂涓篊BC閾炬帴
+    QByteArray adjustedIv(16, '\0');
+
+    QByteArray encrypted = plaintext;
+    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());
+
+    // 绾ぇ鍐欏瓧姣嶇紪鐮侊細16瀛楄妭瀵嗘枃 鈫� 28瀛楃锛堣嫢鍏佽鏁板瓧鎹�36瀛楃闆嗭紝闀垮害闄嶅埌25锛�
+    QByteArray encoded = baseNEncode(encrypted, V3_CHARS, 26);
+    return QString::fromLatin1(encoded);
+}
+
+QByteArray ShortCrypto::decryptRaw(const QString &ciphertext, const QByteArray &key)
+{
+    if (key.size() != 16) {
+        qWarning() << "ShortCrypto::decryptRaw: key must be 16 bytes for AES-128";
+        return QByteArray();
+    }
+
+    // 浼樺厛鎸夌函瀛楁瘝琛ㄨВ鐮侊紱鑻ュ惈琛ㄥ瀛楃锛堟棭鏈烞ase85鐗圴3瀵嗛挜锛夊垯鍥為��Base85
+    QByteArray encrypted = baseNDecode(ciphertext, V3_CHARS, 26);
+    if (encrypted.isEmpty()) {
+        encrypted = base85Decode(ciphertext);
+    }
+    if (encrypted.isEmpty()) {
+        qWarning() << "ShortCrypto::decryptRaw: decode failed";
+        return QByteArray();
+    }
+    if (encrypted.size() % 16 != 0) {
+        qWarning() << "ShortCrypto::decryptRaw: decoded data size not aligned to block size:"
+                   << encrypted.size();
+        return QByteArray();
+    }
+
+    QByteArray adjustedIv(16, '\0');
+    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());
+    return decrypted;
+}
+
+QByteArray ShortCrypto::baseNEncode(const QByteArray &data, const char *alphabet, int base)
+{
+    // 鎶婃暣娈靛ぇ绔瓧鑺傚簭褰撲綔涓�涓ぇ鏁存暟锛岄�愭闄や互base鍙栦綑鏁�
+    QByteArray num = data;
+    QByteArray remainders;
+
+    bool isZero = false;
+    while (!isZero) {
+        isZero = true;
+        unsigned int carry = 0;
+        for (int i = 0; i < num.size(); ++i) {
+            unsigned int cur = (carry << 8) | static_cast<unsigned char>(num.at(i));
+            num[i] = static_cast<char>(cur / static_cast<unsigned int>(base));
+            carry = cur % static_cast<unsigned int>(base);
+            if (num.at(i) != 0) isZero = false;
+        }
+        if (isZero && remainders.isEmpty()) break; // 鍏ㄩ浂杈撳叆
+        remainders.append(alphabet[static_cast<int>(carry)]);
+        if (isZero) break;
+    }
+    if (remainders.isEmpty()) remainders.append(alphabet[0]);
+
+    // 杩樺師涓洪珮浣嶅湪鍓嶏紝骞剁敤alphabet[0]琛ラ綈鍥哄畾浣嶆暟锛堝墠瀵奸浂锛�
+    QByteArray result = remainders;
+    std::reverse(result.begin(), result.end());
+    int minimalLen = static_cast<int>(qCeil(data.size() * 8.0 * qLn(2.0) / qLn(static_cast<double>(base))));
+    if (result.size() < minimalLen) {
+        result.prepend(QByteArray(minimalLen - result.size(), alphabet[0]));
+    }
+    return result;
+}
+
+QByteArray ShortCrypto::baseNDecode(const QString &text, const char *alphabet, int base)
+{
+    // 寤虹珛瀛楃绱㈠紩琛�
+    int charToVal[256];
+    memset(charToVal, -1, sizeof(charToVal));
+    for (int i = 0; i < base; ++i) {
+        charToVal[static_cast<unsigned char>(alphabet[i])] = i;
+    }
+
+    // Horner娉曞垯锛歯um = num * base + v锛堝ぇ绔瓧鑺傚簭锛�
+    QByteArray num(16, '\0');
+    QByteArray input = text.toLatin1();
+    for (int i = 0; i < input.size(); ++i) {
+        int v = charToVal[static_cast<unsigned char>(input.at(i))];
+        if (v < 0) {
+            qWarning() << "ShortCrypto::baseNDecode: invalid character:" << QChar(input.at(i));
+            return QByteArray();
+        }
+        unsigned int carry = static_cast<unsigned int>(v);
+        for (int b = num.size() - 1; b >= 0; --b) {
+            unsigned int cur = (static_cast<unsigned int>(static_cast<unsigned char>(num.at(b))) * static_cast<unsigned int>(base)) + carry;
+            num[b] = static_cast<char>(cur & 0xFF);
+            carry = cur >> 8;
+        }
+        if (carry != 0) {
+            qWarning() << "ShortCrypto::baseNDecode: value overflows 128 bits";
+            return QByteArray();
+        }
+    }
+
+    // 淇濇寔16瀛楄妭瀹氬锛堝墠瀵奸浂鏈夋剰涔夛級锛岃皟鐢ㄦ柟鎸夊浐瀹氬潡闀垮鐞�
+    return num;
+}
+
 QByteArray ShortCrypto::base85Encode(const QByteArray &data)
 {
     QByteArray result;
diff --git a/shortcrypto.h b/shortcrypto.h
index 9f0756e..f34dcdd 100644
--- a/shortcrypto.h
+++ b/shortcrypto.h
@@ -29,12 +29,37 @@
      */
     static QByteArray decrypt(const QString &ciphertext, const QByteArray &key, const QByteArray &iv = QByteArray());
 
+    /**
+     * @brief 鏃犲~鍏呭姞瀵嗭紙V3涓撶敤锛�
+     * @param plaintext 鍘熷鏄庢枃锛岄暱搴﹀繀椤绘槸16鐨勫�嶆暟锛�16瀛楄妭鏄庢枃 鈫� 16瀛楄妭瀵嗘枃锛�
+     * @param key 16瀛楄妭瀵嗛挜锛圓ES-128锛�
+     * @return 绾ぇ鍐欏瓧姣嶇紪鐮佺殑瀵嗘枃瀛楃涓诧紙A-Z锛�26瀛楃闆嗭級锛�16瀛楄妭鏄庢枃鎭板ソ杈撳嚭28瀛楃
+     * @note 涓嶅仛PKCS7濉厖锛�16瀛楄妭鏄庢枃鑻ヨ蛋濉厖浼氭墿鎴�32瀛楄妭
+     * @note 鑻ユ兂缂╃煭鍒�25瀛楃锛屾妸V3_CHARS鎹㈡垚"A-Z0-9"骞舵妸base鏀逛负36鍗冲彲
+     */
+    static QString encryptRaw(const QByteArray &plaintext, const QByteArray &key);
+
+    /**
+     * @brief 鏃犲~鍏呰В瀵嗭紙V3涓撶敤锛�
+     * @param ciphertext 绾ぇ鍐欏瓧姣嶇紪鐮佺殑瀵嗘枃锛堝吋瀹规棭鏈烞ase85/绾瓧姣嶇増V3瀵嗘枃锛岃嚜鍔ㄥ洖閫�锛�
+     * @param key 16瀛楄妭瀵嗛挜锛圓ES-128锛�
+     * @return 鍘熷鏄庢枃锛堥暱搴︿笌瀵嗘枃涓�鑷达級锛屽畬鏁存�х敱涓婂眰CRC鏍¢獙淇濊瘉
+     */
+    static QByteArray decryptRaw(const QString &ciphertext, const QByteArray &key);
+
 private:
     // Base85 瀛楃闆嗭紙RFC 1924 鍙樹綋锛屼笉鍚紩鍙�/閫楀彿/鍙ョ偣/鏂滄潬锛岄伩鍏岼SON/XML杞箟闂锛�
     static const char *BASE85_CHARS;
 
+    // V3 瀵嗘枃瀛楃闆嗭細绾ぇ鍐欏瓧姣嶏紝涓嶅惈鏁板瓧/灏忓啓/鐗规畩瀛楃锛�26瀛楃闆嗭紝16瀛楄妭鈫�28瀛楃锛�
+    static const char *V3_CHARS;
+
     static QByteArray base85Encode(const QByteArray &data);
     static QByteArray base85Decode(const QString &text);
+
+    // 浠绘剰杩涘埗鐨勫ぇ鏁扮紪瑙g爜锛堟暣娈靛瓧鑺傚簭浣滀负澶ф暣鏁帮紝鍓嶅闆朵互alphabet[0]琛ラ綈鍥哄畾浣嶆暟锛�
+    static QByteArray baseNEncode(const QByteArray &data, const char *alphabet, int base);
+    static QByteArray baseNDecode(const QString &text, const char *alphabet, int base);
 };
 
 #endif // SHORTCRYPTO_H

--
Gitblit v1.9.1