License系统设计(二)

本文讲解了License Generator的实现,它采用QT实现,需导入加解密DLL。介绍了导出导入库设计、初始化、预览、加密和解密的实现。还补充了‘Qt非Load方式加载DLL’的方法,包括在QCreator中添加库及修改代码等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://blog.youkuaiyun.com/Sagittarius_Warrior/article/details/53502359

本文主要讲解License Generator的实现,总体设计请参考前一篇文章。

一、导出导入库

    License Generator是采用QT实现的,它需要导入前面的加解密DLL。导入库的设计如下:

#ifndef AES_DLL_H
#define AES_DLL_H

#ifdef AES_IMPORT
#define AES_API extern "C" __declspec(dllexport)
#else
#define AES_API extern "C" __declspec(dllimport)
#endif

#include <string>
using std::string;

class IEncryptor
{
public:
    virtual void SetKey(unsigned char * key, unsigned char * iv, int length) = 0;

    // encrypt the plainText and generate a file, the plainText should be a string with '\0' end
    virtual bool EncryptString2File(const char * plainText, const char * outFilename) = 0;

    // decyrpt the file and output the recover, you may calculate the size of the file and allocate the space for recover
    virtual bool DecryptFile2String(const char * decFilename, char * recoverText) = 0;
};

AES_API IEncryptor* CreateEncryptor();
AES_API void ReleaseEncryptor(IEncryptor* pEncryptor);

typedef IEncryptor* (*pfnCreateEncryptor)();
typedef void (*pfnReleaseEncryptor)(IEncryptor*);

#endif    // AES_DLL_H


    它主要包括两个导出函数,和一个接口类。这两个导出函数主要复杂管理类对象,主要功能还是在这个接口类中。

这个接口类提供了三个接口:

1)设置加解密的密匙;

2)加密字符串并生成加密文件;

3)将加密文件解密,并输出字符串;


二、初始化

    我将加密库的载入和密匙的设置放到MainWindow的构造函数中,如下:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_library("EncryptorDll.dll"),
    m_pEncryptor(nullptr)
{
    ui->setupUi(this);
    QString currentDate = (QDate::currentDate()).toString("yyyy/MM/dd");
    QString Deadline = (QDate::currentDate().addMonths(1)).toString("yyyy/MM/dd");
    ui->lineEdit_6->setText(currentDate);
    ui->lineEdit_7->setText(Deadline);
    ui->lineEdit_8->setText(currentDate);

    unsigned char key[]    = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,    0x09,0x0A, 0x0B,0x0C,0x0D,0x0E,0x0F,0x10};
    //AES::DEFAULT_KEYLENGTH
    unsigned char iv[]    = {0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,    0x07,0x06, 0x05,0x04,0x03,0x02,0x01,0x10};
    int keysize = 16;

    m_library.load();
    if (m_library.isLoaded())
    {
        pfnCreateEncryptor pCreate = (pfnCreateEncryptor)m_library.resolve("CreateEncryptor");

        if (pCreate)
        {
            m_pEncryptor = pCreate();
            m_pEncryptor->SetKey(key,iv,keysize);
        }
    }
}


    加解密DLL库载入成功后,会解析出导入函数“CreateEncryptor”,然后调用该函数,创建真正的加解密类对象,并设置密匙。


三、预览

    下面是“Preview”控件的响应函数

void MainWindow::on_btnPreview_clicked()
{
    QString strPlain{"f0f0,"};
    int count = 8;
    QLabel* arrLabel[8] = {ui->label_1,ui->label_2,ui->label_3,ui->label_4,
                         ui->label_5,ui->label_6,ui->label_7,ui->label_8};
    QLineEdit* arrLine[8] = {ui->lineEdit_1,ui->lineEdit_2,ui->lineEdit_3,ui->lineEdit_4,
                           ui->lineEdit_5,ui->lineEdit_6,ui->lineEdit_7,ui->lineEdit_8};

    for (int i = 0; i < count; ++i)
    {
        strPlain += arrLabel[i]->text();
        strPlain += arrLine[i]->text();
        strPlain += ',';
    }
    strPlain += "0f0f";
    ui->plaintext->setPlainText(strPlain);
}


四、加密和解密

   下面是加密和解密按键的响应函数

void MainWindow::on_btnEncrypt_clicked()
{
    string plainText = ui->plaintext->toPlainText().toStdString();

    string fileName = ui->lineEdit_3->text().toStdString() + ".license";

    if (m_pEncryptor->EncryptString2File(plainText.c_str(), fileName.c_str()))
    {
        ui->ciphertext->setPlainText("Encrypt succeed!");
    }
    else
    {
        ui->ciphertext->setPlainText("Encrypt failed!");
    }
}

void MainWindow::on_btnDecrypt_clicked()
{  
    string fileName = ui->lineEdit_3->text().toStdString() + ".license";
    QFileInfo fileInfo(fileName.c_str());
    char * recover = new char[fileInfo.size()];
    if (m_pEncryptor->DecryptFile2String(fileName.c_str(), recover))
    {
        ui->recovertext->setPlainText(QString(recover));
    }
    else
    {
        ui->recovertext->setPlainText(QString("Recover failed!"));
    }
}


五、补充说明

    原始的Cryptoo++库,推荐用静态库的方式嵌入程序,但是,我之前一直没在Qt中尝试成功过“静态库”的加载,甚至“动态链接库的非Load加载方式”也多次尝试失败。因此,逼得我设计除了“Interface Class”的方式,并在Qt中用QLibrary加载VS生成的DLL。

    今天,我偷闲又试验了一把“Qt非Load方式加载DLL”,竟然成功了,特此补充。我还是用这个License工程为实验对象。“Qt非Load方式加载DLL”其实也不复杂,可以分为三步,事实上,静态库也可以按这个方法加载。

1,使用QCreator,打开宿主工程,在“项目”窗口,右键“项目目录树的根节点”,选择“添加库”。

2,在弹出来的对话框中,选择“库类型”为“外部库”,然后选择待添加的库的路径。

 

注:仔细观察上图,它是可以选择静态库的。


3,点击“下一步”,Qcreator将在*.pro文件添加以下代码

 

    事实上,Qt非Load方式加载DLL仅需要添加这些代码。


注:做完以上工作,即可以加载DLL了。下面,我再以LicenseSystem为例,修改代码如下:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    //m_library("EncryptorDll.dll"),
    m_pEncryptor(nullptr)
{
    ui->setupUi(this);
    QString currentDate = (QDate::currentDate()).toString("yyyy/MM/dd");
    QString Deadline = (QDate::currentDate().addMonths(1)).toString("yyyy/MM/dd");
    ui->lineEdit_6->setText(currentDate);
    ui->lineEdit_7->setText(Deadline);
    ui->lineEdit_8->setText(currentDate);

    unsigned char key[]    = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,    0x09,0x0A, 0x0B,0x0C,0x0D,0x0E,0x0F,0x10};
    //AES::DEFAULT_KEYLENGTH
    unsigned char iv[]    = {0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,    0x07,0x06, 0x05,0x04,0x03,0x02,0x01,0x10};
    int keysize = 16;

//    m_library.load();
//    if (m_library.isLoaded())
//    {
//        pfnCreateEncryptor pCreate = (pfnCreateEncryptor)m_library.resolve("CreateEncryptor");

//        if (pCreate)
//        {
//            m_pEncryptor = pCreate();
//            m_pEncryptor->SetKey(key,iv,keysize);
//        }
//    }
    m_pEncryptor = CreateEncryptor();
    m_pEncryptor->SetKey(key,iv,keysize);
}

MainWindow::~MainWindow()
{
    delete ui;
//    if (m_library.isLoaded())
//    {
//        pfnReleaseEncryptor pRelease = (pfnReleaseEncryptor)m_library.resolve("ReleaseEncryptor");

//        if (pRelease)
//        {
//            pRelease(m_pEncryptor);
//        }
//        m_library.unload();
//    }
    ReleaseEncryptor(m_pEncryptor);
}


注:以上注释了QLibrary和Load,直接调用DLL中的接口函数。
---------------------
作者:Sagittarius_Warrior
来源:优快云
原文:https://blog.youkuaiyun.com/Sagittarius_Warrior/article/details/53502359
版权声明:本文为博主原创文章,转载请附上博文链接!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值