asyncdecrypttask.h
#ifndef ASYNCDECRYPTTASK_H
#define ASYNCDECRYPTTASK_H
#include <QAtomicInteger>
#include <QObject>
#include <QRunnable>
class AsyncDecryptTask : public QObject, public QRunnable {
Q_OBJECT
public:
explicit AsyncDecryptTask(const QString &inputPath, const QString &outputPath,
const QByteArray &key, const QByteArray &iv,
QAtomicInt &cancelFlag);
signals:
void progressChanged(qint64 bytesProcessed);
void finished(bool success, const QString &error);
protected:
void run() override;
private:
QString m_inputPath;
QString m_outputPath;
QByteArray m_key;
QByteArray m_iv;
QAtomicInt &m_cancelFlag;
};
#endif // ASYNCDECRYPTTASK_H
asyncencrypttask.h
#ifndef ASYNCENCRYPTTASK_H
#define ASYNCENCRYPTTASK_H
#include <QAtomicInteger>
#include <QFile>
#include <QObject>
#include <QRunnable>
#include <openssl/evp.h>
#include <atomic>
class AsyncEncryptTask : public QObject, public QRunnable {
Q_OBJECT
public:
explicit AsyncEncryptTask(const QString &inputPath, const QString &outputPath,
qint64 readOffset, qint64 chunkSize,
const QByteArray &key, const QByteArray &iv,
QAtomicInt &cancelFlag);
signals:
void progressChanged(qint64 bytesProcessed);
void finished(bool success, const QString &error);
protected:
void run() override;
private:
// 成员变量
QString m_inputPath;
QString m_outputPath;
qint64 m_readOffset;
qint64 m_chunkSize;
QByteArray m_key;
QByteArray m_iv;
QAtomicInt m_cancelFlag;
};
#endif // ASYNCENCRYPTTASK_H
config.h
#pragma once
constexpr auto AES_BLOCK_SIZE_16 = 16;
constexpr auto AES_KEY_SIZE_32 = 32;
constexpr auto RSA_KEY_SIZE_2048 = 2048;
// 设置文件缓冲区大小
constexpr auto FILE_BUFFER_SIZE = 4096;
constexpr auto CONFIG_MAX_CHUNK_SIZE = 2LL * 1024 * 1024 * 1024;// 2GB
coreservice.h
#pragma once
#include "encryptiondecryptionmanager.h"
#include "keymanager.h"
#include "qtencryptdecrypt.h"
#include <atomic>
#include <QObject>
class CoreService : public QObject {
Q_OBJECT
public:
explicit CoreService(QObject *parent = nullptr);
// 加密服务
void encryptTextServer(const QString &text, const QString &recipient);
void encryptFileServer(const QString &filePath, QString &outPath,
const QString &recipient);
void encryptLargeFileServer(const QString &filePath, QString &outPath,
const QString &recipient);
// 解密服务
void decryptTextServer(const QString &ciphertext);
void decryptFileServer(const QString &filePath, QString &outPath);
void decryptLargeFileServer(const QString &metaFilePath, QString &outPath);
// 密钥管理
KeyManager *keyManager() const { return m_keyManager; }
signals:
void encryptionProgress(qint64 total, qint64 processed);
void decryptionProgress(qint64 total, qint64 processed);
void textEncrypted(const QString &ciphertext);
void textDecrypted(const QString &plaintext);
void fileEncrypted(bool success, const QString &message);
void fileDecrypted(bool success, const QString &message);
void errorOccurred(const QString &error);
public:
KeyManager *m_keyManager;
EncryptionDecryptionManager *m_cryptoManager; // 单文件加密解密管理器
QtEncryptDecrypt *m_crypto; // 密钥算法及文本,分块文件加密解密器
private:
std::atomic<bool> m_operating{false};
};
decrypttask.h
#ifndef DECRYPTTASK_H
#define DECRYPTTASK_H
#include <QAtomicInteger>
#include <QElapsedTimer>
#include <QFile>
#include <QMutex>
#include <QObject>
#include <QRunnable>
#include <QWaitCondition>
#include <openssl/evp.h>
class DecryptTask : public QObject, public QRunnable {
Q_OBJECT
public:
enum State { Running, Paused, Stopped, Completed };
explicit DecryptTask(const QString &inputPath, int partIndex,
const QByteArray &key, const QByteArray &iv,
QVector<QByteArray> &outputBuffers, QMutex &bufferMutex,
QAtomicInt &cancelFlag, QObject *parent = nullptr);
void run() override;
void pause();
void resume();
void cancel();
// 状态查询
State state() const;
qint64 processedBytes() const;
qint64 totalBytes() const;
double speed() const;
int partIndex() const;
signals:
void progressUpdated(int partIndex, qint64 bytesProcessed);
void completed(int partIndex, bool success);
void errorOccurred(const QString &message);
private:
// 内存映射处理
bool processMappedData(uchar *data, qint64 size, EVP_CIPHER_CTX *ctx,
QByteArray &buffer);
QString m_inputPath;
int m_partIndex;
QByteArray m_key;
QByteArray m_iv;
QVector<QByteArray> &m_outputBuffers;
QMutex &m_bufferMutex;
QAtomicInt &m_cancelFlag;
mutable QMutex m_stateMutex;
QWaitCondition m_pauseCondition;
State m_state = Running;
qint64 m_processedBytes = 0;
qint64 m_totalBytes = 0;
QElapsedTimer m_timer;
};
#endif // DECRYPTTASK_H
encryptiondecryptionmanager.h
#ifndef ENCRYPTIONDECRYPTIONMANAGER_H
#define ENCRYPTIONDECRYPTIONMANAGER_H
#include <QAtomicInteger>
#include <QObject>
#include <QThreadPool>
#include <QDebug>
class EncryptionDecryptionManager : public QObject {
Q_OBJECT
public:
explicit EncryptionDecryptionManager(QObject *parent = nullptr);
void encryptFile(const QString &inputPath, const QString &outputPath,
const QByteArray &key, const QByteArray &iv);
void decryptFile(const QString &inputPath, const QString &outputPath,
const QByteArray &key, const QByteArray &iv);
void cancelAll();
signals:
void progressChanged(qint64 totalBytes, qint64 bytesProcessed);
void encryptionOperationFinished(bool success, const QString &message);
void decryptionOperationFinished(bool success, const QString &message);
private:
QThreadPool m_threadPool;
QAtomicInt m_cancelFlag;
qint64 m_totalBytes = 0;
qint64 m_processedBytes = 0;
};
#endif // ENCRYPTIONDECRYPTIONMANAGER_H
encrypttask.h
#ifndef ENCRYPTTASK_H
#define ENCRYPTTASK_H
#include <QByteArray>
#include <QElapsedTimer>
#include <QMutex>
#include <QObject>
#include <QRunnable>
#include <QWaitCondition>
class EncryptTask : public QObject, public QRunnable {
Q_OBJECT
public:
enum State { Running, Paused, Stopped, Completed };
EncryptTask(const QString &inputPath, const QString &outputPath,
qint64 readOffset, qint64 chunkSize, const QByteArray &key,
const QByteArray &iv, QAtomicInt &cancelFlag,
QObject *parent = nullptr);
void run() override;
void pause();
void resume();
void cancel();
State state() const;
qint64 processedBytes() const;
qint64 totalBytes() const;
double speed() const;
signals:
void progressUpdated(qint64 bytesProcessed);
signals:
void completed(bool success);
signals:
void errorOccurred(const QString &message);
public:
QString m_inputPath;
QString m_outputPath;
qint64 m_readOffset;
qint64 m_chunkSize;
QByteArray m_key;
QByteArray m_iv;
QAtomicInt &m_cancelFlag;
mutable QMutex m_stateMutex;
QWaitCondition m_pauseCondition;
State m_state = Running;
qint64 m_processedBytes = 0;
QElapsedTimer m_timer;
};
#endif // ENCRYPTTASK_H
functionwidget.h
#pragma once
#include <QWidget>
#include <QPushButton>
#include <QTextBrowser>
#include <QComboBox>
#include <QMessageBox>
#include <QFileDialog>
#include <QGridLayout>
class FunctionWidget : public QWidget
{
Q_OBJECT
public:
FunctionWidget(QWidget *parent);
void initFunctionWidget();
~FunctionWidget();
public:
QComboBox* comBoxUserList;
QTextBrowser* browserUserAndKeyInfo;
QPushButton *btnEncrypt;
QPushButton *btnEncryptBlockFile;
QPushButton *btnEncryptFile;
QPushButton *btnDecrypt;
QPushButton *btnDecryptBlockFile;
QPushButton *btnDecryptFile;
QPushButton *btnCopyPlaintext;
QPushButton *btnCopyCiphertext;
QPushButton *btnKeyGenerate;
QPushButton *btnImportKey;
QPushButton *btnSelectSendUser;
QPushButton *btnOpenWorkspace;
QGridLayout *mainLayout;
};
keymanager.h
#pragma once
#include "qtencryptdecrypt.h"
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMap>
#include <QObject>
#include <QString>
#include <QTextStream>
#include <QWidget>
struct UserKeyInfo {
QString username;
QString rsaPublicKey;
};
class KeyManager : public QObject {
Q_OBJECT
public:
explicit KeyManager(QObject *parent = nullptr);
// 生成用户密钥对
bool generateUserKeys(const QString &username, QString &errorMsg,
QString &outFilePath);
// 加载外部密钥文件
bool importKeyFile(const QString &filePath);
// 获取用户列表
QList<UserKeyInfo> getAvailableUsers() const;
// 获取本地密钥存储路径
static QString getKeyStoragePath();
// 提取本地存储的RSA私钥
bool extractPrivateKey(QString &privateKey, QString &errorMsg);
// 选择本地文件*.privatey以成为当前用户*
bool selectCurrentUserPrivateKey(QString filename, QString &errorMsg);
// currentUser: 当前登录的用户名(发送者)
QString m_currentUser;
// 设置默认的当前登录的用户名(发送者)
bool setDefaultCurrentUser();
// 加载所有本地密钥
void loadLocalKeys();
// 初始化存储目录
bool initStorage();
// 保存密钥文件
bool saveKeyPackage(const UserKeyInfo &info);
signals:
void userKeysUpdated();
signals:
void currentUserChanged();
private:
QMap<QString, UserKeyInfo> m_users; // username -> KeyInfo
QtEncryptDecrypt *m_crypto;
~KeyManager();
};
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "coreservice.h"
#include "encryptiondecryptionmanager.h"
#include "functionwidget.h"
#include "keymanager.h"
#include "textwidget.h"
#include <QByteArray>
#include <QClipboard>
#include <QComboBox>
#include <QCryptographicHash>
#include <QDateTime>
#include <QDesktopServices>
#include <QFile>
#include <QFileDialog>
#include <QGridLayout>
#include <QImage>
#include <QInputDialog>
#include <QLabel>
#include <QLineEdit>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QProgressDialog>
#include <QPushButton>
#include <QStatusBar>
#include <QTextBrowser>
#include <QTextEdit>
#include <QUrl>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
// 核心服务
CoreService *m_coreService;
// Ui组件
Ui::MainWindow *ui;
QWidget *centralWidget;
TextWidget *textWidget;
FunctionWidget *functionWidget;
QGridLayout *gridLayout;
QString browerConstText;
QString browerVarText;
qint64 maxProgressValue;
qint64 currentProgressValue;
// 状态栏标签
QLabel *m_userLabel;
QLabel *m_plainTextLenLabel;
QLabel *m_cipherTextLenLabel;
QLabel *m_timeLabel;
QLabel *m_taskStatusLabel;
QLabel *m_permanentMsgLabel;
QProgressDialog *m_progressDialog;
public:
// 初始化界面和资源
void initUIAndSource();
// 初始化数据
void initData();
// 初始化连接
void initConnect();
// 初始化菜单栏
void initMenuBar();
// 初始化工具栏
void initToolBar();
// 初始化状态栏
void initStatusBar();
private slots:
void onEncryptBtn();
void onEncryptClickedAsyncBlockFile();
void onEncryptClickedAsyncFile();
void onDecryptBtn();
void onDecryptClickedAsyncBlockFile();
void onDecryptClickedAsyncFile();
void onGenerateKeys();
void onImportKey();
void refreshUserList();
void onCopyPlainTextToClipboard();
void onCopyCipherTextToClipboard();
void onSelectSendUser();
void onOpenWorkspace();
void onAbout();
};
#endif // MAINWINDOW_H
paralleldecryptor.h
#ifndef PARALLELDECRYPTOR_H
#define PARALLELDECRYPTOR_H
#include <QObject>
#include <QThreadPool>
#include <QVector>
#include <QMutex>
class DecryptTask;
class ParallelDecryptor : public QObject {
Q_OBJECT
public:
explicit ParallelDecryptor(QObject *parent = nullptr);
~ParallelDecryptor();
bool isRunning() const;
qint64 totalProgress() const;
qint64 totalBytes() const;
double overallSpeed() const;
public slots:
void decryptFile(const QStringList &encryptedParts, const QString &outputPath,
const QByteArray &key, const QByteArray &iv);
void pauseAll();
void resumeAll();
void cancelAll();
signals:
void progressChanged(qint64 totalBytes, qint64 bytesProcessed);
signals:
void completed(bool success);
signals:
void errorOccurred(const QString &message);
private slots:
void handleTaskProgress(int partIndex, qint64 bytes);
void handleTaskCompletion();
private:
bool writeFinalOutput(const QString &path);
QThreadPool m_threadPool;
QVector<DecryptTask *> m_tasks;
QVector<QByteArray> m_outputBuffers;
QMutex m_bufferMutex;
QAtomicInt m_cancelFlag;
qint64 m_totalBytes = 0;
qint64 m_processedBytes = 0;
QElapsedTimer m_totalTimer;
QString m_finalOutputPath;
public:
// 新增访问方法
QString lastError() const { return m_lastError; }
private:
QString m_lastError;
};
#endif // PARALLELDECRYPTOR_H
parallelencryptor.h
#ifndef PARALLELENCRYPTOR_H
#define PARALLELENCRYPTOR_H
#include <QObject>
#include <QThreadPool>
#include <QVector>
class EncryptTask;
class ParallelEncryptor : public QObject {
Q_OBJECT
public:
explicit ParallelEncryptor(QObject *parent = nullptr);
~ParallelEncryptor();
bool isRunning() const;
qint64 totalProgress() const;
double overallSpeed() const;
public slots:
void encryptFile(const QString &inputPath, const QString &outputBasePath,
const QByteArray &key, const QByteArray &iv);
void pauseAll();
void resumeAll();
void cancelAll();
signals:
void progressChanged(qint64 totalBytes, qint64 bytesProcessed);
signals:
void completed(bool success);
signals:
void errorOccurred(const QString &message);
private slots:
void handleTaskProgress(qint64 bytes);
void handleTaskCompletion();
private:
QThreadPool m_threadPool;
QVector<EncryptTask *> m_tasks;
QAtomicInt m_cancelFlag;
qint64 m_totalBytes = 0;
qint64 m_processedBytes = 0;
QElapsedTimer m_totalTimer;
public:
// 新增访问方法
QStringList encryptedParts() const { return m_encryptedParts; }
QString lastError() const { return m_lastError; }
private:
QStringList m_encryptedParts;
QString m_lastError;
};
#endif // PARALLELENCRYPTOR_H
qtencryptdecrypt.h
#pragma once
#include "config.h"
#include "paralleldecryptor.h"
#include "parallelencryptor.h"
#include <QByteArray>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QObject>
#include <QString>
#include <QtGlobal>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <vector>
class QtEncryptDecrypt : public QObject {
Q_OBJECT;
public:
QtEncryptDecrypt(QObject *parent);
~QtEncryptDecrypt();
// AES
bool generateAESKey(QString &keyStr, QString &ivStr, QString &errMessage);
// AES加密文本
bool encryptPlaintext_AES(const QString &plaintext, const QString &keyStr,
const QString &ivStr, QString &ciphertext,
QString &errMessage);
// AES解密密文
bool decryptCiphertext_AES(const QString &ciphertext, const QString &keyStr,
const QString &ivStr, QString &plaintext,
QString &errMessage);
// AES加密文件
bool encryptFile_AES(const QString &inputFile, const QString &outputFile,
const QString &keyStr, const QString &ivStr,
QString &errMessage);
// AES解密文件
bool decryptFile_AES(const QString &inputFile, const QString &outputFile,
const QString &keyStr, const QString &ivStr,
QString &errMessage);
// 异步AES加密接口
void encryptFileChunked_AES(const QString &inputPath,
const QString &outputBasePath,
const QByteArray &key, const QByteArray &iv);
// 异步AES解密接口
void decryptFileChunked_AES(const QString &outputFileName,
const QByteArray &key, const QByteArray &iv,
const QStringList &encryptedParts);
// RSA
bool generateRSAKeyPair(QString &pubKeyStr, QString &privKeyStr,
QString &errMessage);
// RSA加密AES
bool encryptPlaintext_RSA(const QString &plaintext, const QString &pubKey,
QString &ciphertext, QString &errMessage);
// RSA解密AES
bool decryptCiphertext_RSA(const QString &ciphertext, const QString &privKey,
QString &plaintext, QString &errMessage);
signals:
void encryptionFinished(bool success, const QStringList &parts,
const QString &error);
signals:
void decryptionFinished(bool success, const QString &error);
public:
ParallelEncryptor *m_encryptor = nullptr;
ParallelDecryptor *m_decryptor = nullptr;
// 在QtEncryptDecrypt类声明中添加:
signals:
void encryptionProgressChanged(qint64 total, qint64 processed);
signals:
void decryptionProgressChanged(qint64 total, qint64 processed);
public slots:
void cancelEncryption() {
if (m_encryptor) {
m_encryptor->cancelAll();
}
}
void cancelDecryption() {
if (m_decryptor) {
m_decryptor->cancelAll();
}
}
};
resource.h
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by CipherClient.rc
// 新对象的下一组默认值
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
test.h
#pragma once
#include <QObject>
class Test : public QObject
{
Q_OBJECT
public:
Test(QObject *parent);
~Test();
};
textwidget.h
#pragma once
#include <QGroupBox>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QWidget>
class TextWidget : public QWidget {
Q_OBJECT
public:
TextWidget(QWidget* parent);
void initTextWidget();
~TextWidget();
public:
QTextEdit* plainTextEdit;
QTextEdit* cipherTextEdit;
QGroupBox* plainTextGroupBox;
QGroupBox* cipherTextGroupBox;
QVBoxLayout* plainTextLayout;
QVBoxLayout* cipherTextLayout;
QVBoxLayout* mainLayout;
};
ui_mainwindow.h
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 6.8.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralwidget;
QMenuBar *menubar;
QStatusBar *statusbar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName("MainWindow");
MainWindow->resize(800, 600);
centralwidget = new QWidget(MainWindow);
centralwidget->setObjectName("centralwidget");
MainWindow->setCentralWidget(centralwidget);
menubar = new QMenuBar(MainWindow);
menubar->setObjectName("menubar");
menubar->setGeometry(QRect(0, 0, 800, 18));
MainWindow->setMenuBar(menubar);
statusbar = new QStatusBar(MainWindow);
statusbar->setObjectName("statusbar");
MainWindow->setStatusBar(statusbar);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
asyncdecrypttask.cpp
#include "asyncdecrypttask.h"
#include <QDebug>
#include <QFile>
#include <openssl/evp.h>
#define BUFFER_SIZE (4 * 1024 * 1024) // 4MB缓冲区
AsyncDecryptTask::AsyncDecryptTask(const QString &inputPath,
const QString &outputPath,
const QByteArray &key, const QByteArray &iv,
QAtomicInt &cancelFlag)
: m_inputPath(inputPath), m_outputPath(outputPath), m_key(key), m_iv(iv),
m_cancelFlag(cancelFlag) {
setAutoDelete(true);
}
void AsyncDecryptTask::run() {
QFile inFile(m_inputPath);
QFile outFile(m_outputPath);
EVP_CIPHER_CTX *ctx = nullptr;
bool success = true;
QString errorMsg = "";
qint64 totalProcessed = 0;
do {
// 打开加密文件
if (!inFile.open(QIODevice::ReadOnly)) {
errorMsg = "AsyncDecryptTask: Unable to open encrypted file";
success = false;
break;
}
// 创建输出文件
if (!outFile.open(QIODevice::WriteOnly)) {
errorMsg = "AsyncDecryptTask: Unable to create decryption file";
success = false;
break;
}
// 初始化解密上下文
ctx = EVP_CIPHER_CTX_new();
if (!ctx ||
!EVP_DecryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(m_key.constData()),
reinterpret_cast<const unsigned char *>(m_iv.constData()))) {
errorMsg = "AsyncDecryptTask: Failed to resolve dense initialization";
success = false;
break;
}
// 解密处理循环
QVector<unsigned char> inBuf(BUFFER_SIZE);
QVector<unsigned char> outBuf(BUFFER_SIZE + EVP_MAX_BLOCK_LENGTH);
while (!inFile.atEnd() && !m_cancelFlag.loadAcquire()) {
// 读取加密数据
qint64 bytesRead =
inFile.read(reinterpret_cast<char *>(inBuf.data()), BUFFER_SIZE);
if (bytesRead < 0) {
errorMsg = "AsyncDecryptTask: File read error";
success = false;
break;
}
// 解密数据
int outLen = 0;
if (!EVP_DecryptUpdate(ctx, outBuf.data(), &outLen, inBuf.data(),
bytesRead)) {
errorMsg = "AsyncDecryptTask: Decryption process error";
success = false;
break;
}
// 写入解密数据
if (outFile.write(reinterpret_cast<char *>(outBuf.data()), outLen) !=
outLen) {
errorMsg = "AsyncDecryptTask: File write error";
success = false;
break;
}
totalProcessed += bytesRead;
emit progressChanged(bytesRead);
}
// 处理最终块
if (success && !m_cancelFlag.loadAcquire()) {
int finalLen = 0;
if (!EVP_DecryptFinal_ex(ctx, outBuf.data(), &finalLen)) {
errorMsg = "AsyncDecryptTask: Final decryption failed";
success = false;
} else if (finalLen > 0) {
if (outFile.write(reinterpret_cast<char *>(outBuf.data()), finalLen) !=
finalLen) {
errorMsg = "AsyncDecryptTask: Final block write failed";
success = false;
}
}
}
} while (false);
// 清理资源
if (ctx)
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
// 处理取消或失败情况
if (m_cancelFlag.loadAcquire()) {
outFile.remove();
success = false;
errorMsg = "AsyncDecryptTask: Operation cancelled";
emit finished(success, errorMsg);
} else if (!success) {
outFile.remove();
errorMsg = "AsyncDecryptTask: Operation failed: ";
emit finished(success, errorMsg + errorMsg);
} else if (success) {
emit finished(success, errorMsg);
}
}
asyncencrypttask.cpp
#include "asyncencrypttask.h"
#include <QDebug>
#include <QFile>
#define BUFFER_SIZE (4 * 1024 * 1024) // 4MB缓冲区
AsyncEncryptTask::AsyncEncryptTask(const QString &inputPath,
const QString &outputPath, qint64 readOffset,
qint64 chunkSize, const QByteArray &key,
const QByteArray &iv, QAtomicInt &cancelFlag)
: m_inputPath(inputPath), m_outputPath(outputPath),
m_readOffset(readOffset), m_chunkSize(chunkSize), m_key(key), m_iv(iv),
m_cancelFlag(cancelFlag) {
setAutoDelete(true);
}
void AsyncEncryptTask::run() {
QFile inFile(m_inputPath);
QFile outFile(m_outputPath);
EVP_CIPHER_CTX *ctx = nullptr;
bool success = true;
QString errorMsg = "";
qint64 totalProcessed = 0;
do {
// 打开输入文件
if (!inFile.open(QIODevice::ReadOnly)) {
errorMsg = "AsyncEncryptTask: the source file for reading failed";
success = false;
break;
}
// 定位到指定偏移
if (!inFile.seek(m_readOffset)) {
errorMsg = "AsyncEncryptTask: File positioning failed";
success = false;
break;
}
// 创建输出文件
if (!outFile.open(QIODevice::WriteOnly)) {
errorMsg = "AsyncEncryptTask: Unable to create output file";
success = false;
break;
}
// 初始化加密上下文
ctx = EVP_CIPHER_CTX_new();
if (!ctx ||
!EVP_EncryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(m_key.constData()),
reinterpret_cast<const unsigned char *>(m_iv.constData()))) {
errorMsg = "AsyncEncryptTask: Encryption initialization failed";
success = false;
break;
}
// 加密处理循环
QVector<unsigned char> inBuf(BUFFER_SIZE);
QVector<unsigned char> outBuf(BUFFER_SIZE + EVP_MAX_BLOCK_LENGTH);
while (totalProcessed < m_chunkSize && !m_cancelFlag.loadAcquire()) {
// 读取数据
qint64 bytesToRead = qMin(BUFFER_SIZE, m_chunkSize - totalProcessed);
qint64 bytesRead =
inFile.read(reinterpret_cast<char *>(inBuf.data()), bytesToRead);
if (bytesRead <= 0) {
if (bytesRead < 0)
errorMsg = "AsyncEncryptTask: File read error";
break;
}
// 加密数据
int outLen = 0;
if (!EVP_EncryptUpdate(ctx, outBuf.data(), &outLen, inBuf.data(),
bytesRead)) {
errorMsg = "AsyncEncryptTask: Encryption process error";
success = false;
break;
}
// 写入数据
if (outFile.write(reinterpret_cast<char *>(outBuf.data()), outLen) !=
outLen) {
errorMsg = "AsyncEncryptTask: File write error";
success = false;
break;
}
totalProcessed += bytesRead;
emit progressChanged(bytesRead);
}
// 处理最终块
if (success && !m_cancelFlag.loadAcquire()) {
int finalLen = 0;
if (!EVP_EncryptFinal_ex(ctx, outBuf.data(), &finalLen)) {
errorMsg = "AsyncEncryptTask: Final encryption failed";
success = false;
} else if (finalLen > 0) {
if (outFile.write(reinterpret_cast<char *>(outBuf.data()), finalLen) !=
finalLen) {
errorMsg = "AsyncEncryptTask: Final block write failed";
success = false;
}
}
}
} while (false);
// 清理资源
if (ctx)
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
// 处理取消或失败情况
if (m_cancelFlag.loadAcquire()) {
outFile.remove();
success = false;
errorMsg = "AsyncEncryptTask: Operation cancelled";
emit finished(success, errorMsg);
} else if (!success) {
outFile.remove();
errorMsg = "AsyncEncryptTask: Operation failed: ";
emit finished(success, errorMsg);
}else if(success){
emit finished(success, errorMsg);
}
}
coreservice.cpp
#include "coreservice.h"
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QThreadPool>
#include <openssl/err.h>
CoreService::CoreService(QObject *parent) : QObject(parent) {
// 初始化密钥管理器和加密管理器
m_keyManager = new KeyManager(this);
m_cryptoManager = new EncryptionDecryptionManager(this);
m_crypto = new QtEncryptDecrypt(this);
// 设置线程池
QThreadPool::globalInstance()->setMaxThreadCount(QThread::idealThreadCount());
}
// 加密文本
void CoreService::encryptTextServer(const QString &text,
const QString &recipient) {
if (text.isEmpty() || recipient.isEmpty()) {
emit errorOccurred(tr("Text or recipient cannot be empty"));
return;
}
// 获取接收者的公钥
auto users = m_keyManager->getAvailableUsers();
auto it = std::find_if(users.begin(), users.end(), [&](const UserKeyInfo &u) {
return u.username == recipient;
});
if (it == users.end()) {
emit errorOccurred(tr("Recipient not found"));
return;
}
// 生成 AES 密钥和 IV
QString aesKey, aesIV, error;
if (!m_crypto->generateAESKey(aesKey, aesIV, error)) {
emit errorOccurred(error);
return;
}
// 使用接收者的公钥加密 AES 密钥
QString encryptedAesKey;
if (!m_crypto->encryptPlaintext_RSA(aesKey, it->rsaPublicKey, encryptedAesKey,
error)) {
emit errorOccurred(error);
return;
}
// 使用 AES 加密文本
QString encryptedText;
if (!m_crypto->encryptPlaintext_AES(text, aesKey, aesIV, encryptedText,
error)) {
emit errorOccurred(error);
return;
}
// 构建加密数据包
QJsonObject package;
package["key"] = encryptedAesKey;
package["iv"] = aesIV;
package["ciphertext"] = encryptedText;
// 发送加密完成信号
emit textEncrypted(QJsonDocument(package).toJson());
}
// 解密文本
void CoreService::decryptTextServer(const QString &ciphertext) {
if (ciphertext.isEmpty()) {
emit errorOccurred(tr("Ciphertext cannot be empty"));
return;
}
// 解析加密数据包
QJsonDocument doc = QJsonDocument::fromJson(ciphertext.toUtf8());
if (doc.isNull()) {
emit errorOccurred(tr("Invalid ciphertext format"));
return;
}
QJsonObject obj = doc.object();
QString encryptedKey = obj["key"].toString();
QString aesIV = obj["iv"].toString();
QString encryptedText = obj["ciphertext"].toString();
// 获取当前用户的私钥
QString privateKey, error;
if (!m_keyManager->extractPrivateKey(privateKey, error)) {
emit errorOccurred(error);
return;
}
// 使用私钥解密 AES 密钥
QString aesKey;
if (!m_crypto->decryptCiphertext_RSA(encryptedKey, privateKey, aesKey,
error)) {
emit errorOccurred(error);
return;
}
// 使用 AES 解密文本
QString plaintext;
if (!m_crypto->decryptCiphertext_AES(encryptedText, aesKey, aesIV, plaintext,
error)) {
emit errorOccurred(error);
return;
}
// 发送解密完成信号
emit textDecrypted(plaintext);
}
// 加密文件
void CoreService::encryptFileServer(const QString &filePath, QString &outPath,
const QString &recipient) {
if (m_operating)
return;
m_operating = true;
if (filePath.isEmpty() || recipient.isEmpty()) {
emit errorOccurred(tr("File path or recipient cannot be empty"));
return;
}
// 获取接收者的公钥
auto users = m_keyManager->getAvailableUsers();
auto it = std::find_if(users.begin(), users.end(), [&](const UserKeyInfo &u) {
return u.username == recipient;
});
if (it == users.end()) {
emit errorOccurred(tr("Recipient not found"));
return;
}
// 生成 AES 密钥和 IV
QString aesKey, aesIV, error;
if (!m_crypto->generateAESKey(aesKey, aesIV, error)) {
emit errorOccurred(error);
return;
}
// 使用接收者的公钥加密 AES 密钥
QString encryptedAesKey;
if (!m_crypto->encryptPlaintext_RSA(aesKey, it->rsaPublicKey, encryptedAesKey,
error)) {
emit errorOccurred(error);
return;
}
// 加密文件
QString outputFilePath =
outPath + "/" + QFileInfo(filePath).fileName() + ".encrypted";
connect(m_cryptoManager, &EncryptionDecryptionManager::progressChanged,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(
this, [=]() { emit encryptionProgress(total, processed); });
}); // 发送加密进度信号
connect(m_cryptoManager,
&EncryptionDecryptionManager::encryptionOperationFinished, this,
[=](bool success, const QString &message) {
QMetaObject::invokeMethod(this, [=]() {
if (!success) {
emit errorOccurred(message);
} else {
// 保存元数据
QJsonObject metaData;
metaData["key"] = encryptedAesKey;
metaData["iv"] = aesIV;
metaData["original_file"] = QFileInfo(filePath).fileName();
QFile metaFile(outputFilePath + ".meta");
if (!metaFile.open(QIODevice::WriteOnly)) {
emit errorOccurred(tr("Failed to save metadata"));
return;
}
metaFile.write(QJsonDocument(metaData).toJson());
metaFile.close();
m_operating = false;
// 发送加密完成信号
emit fileEncrypted(
true,
tr("File encrypted successfully: %1").arg(outputFilePath));
}
});
});
// 启动加密
m_cryptoManager->encryptFile(filePath, outputFilePath,
QByteArray::fromBase64(aesKey.toLatin1()),
QByteArray::fromBase64(aesIV.toLatin1()));
}
// 解密文件
void CoreService::decryptFileServer(const QString &filePath, QString &outPath) {
if (m_operating)
return;
m_operating = true;
if (filePath.isEmpty()) {
emit errorOccurred(tr("File path cannot be empty"));
return;
}
// 读取元数据
QFile metaFile(filePath + ".meta");
if (!metaFile.open(QIODevice::ReadOnly)) {
emit errorOccurred(tr("Failed to read metadata"));
return;
}
QJsonDocument doc = QJsonDocument::fromJson(metaFile.readAll());
metaFile.close();
if (doc.isNull()) {
emit errorOccurred(tr("Invalid metadata format"));
return;
}
QJsonObject obj = doc.object();
QString encryptedKey = obj["key"].toString();
QString aesIV = obj["iv"].toString();
QString originalFileName = obj["original_file"].toString();
// 获取当前用户的私钥
QString privateKey, error;
if (!m_keyManager->extractPrivateKey(privateKey, error)) {
emit errorOccurred(error);
return;
}
// 使用私钥解密 AES 密钥
QString aesKey;
if (!m_crypto->decryptCiphertext_RSA(encryptedKey, privateKey, aesKey,
error)) {
emit errorOccurred(error);
return;
}
// 解密文件
QString outputFilePath = outPath + "/decrypted_" + originalFileName;
connect(m_cryptoManager, &EncryptionDecryptionManager::progressChanged,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(
this, [=]() { emit decryptionProgress(total, processed); });
}); // 发送解密进度信号
connect(m_cryptoManager,
&EncryptionDecryptionManager::decryptionOperationFinished, this,
[=](bool success, const QString &message) {
QMetaObject::invokeMethod(this, [=]() {
if (!success) {
emit errorOccurred(message);
} else {
m_operating = false;
emit fileDecrypted(
true,
tr("File decrypted successfully: %1").arg(outputFilePath));
}
});
});
// 启动解密
m_cryptoManager->decryptFile(filePath, outputFilePath,
QByteArray::fromBase64(aesKey.toLatin1()),
QByteArray::fromBase64(aesIV.toLatin1()));
}
// 加密大文件(分块加密)
void CoreService::encryptLargeFileServer(const QString &filePath,
QString &outPath,
const QString &recipient) {
if (m_operating)
return;
m_operating = true;
if (filePath.isEmpty() || recipient.isEmpty()) {
emit errorOccurred(tr("File path or recipient cannot be empty"));
return;
}
// 获取接收者的公钥
auto users = m_keyManager->getAvailableUsers();
auto it = std::find_if(users.begin(), users.end(), [&](const UserKeyInfo &u) {
return u.username == recipient;
});
if (it == users.end()) {
emit errorOccurred(tr("Recipient not found"));
return;
}
// 生成 AES 密钥和 IV
QString aesKey, aesIV, error;
if (!m_crypto->generateAESKey(aesKey, aesIV, error)) {
emit errorOccurred(error);
return;
}
// 使用接收者的公钥加密 AES 密钥
QString encryptedAesKey;
if (!m_crypto->encryptPlaintext_RSA(aesKey, it->rsaPublicKey, encryptedAesKey,
error)) {
emit errorOccurred(error);
return;
}
QString outputFilePath =
outPath + "/" + QFileInfo(filePath).fileName() + ".encrypted";
connect(m_crypto, &QtEncryptDecrypt::encryptionProgressChanged, this,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(
this, [=]() { emit encryptionProgress(total, processed); });
}); // 连接进度条槽函数
connect(m_crypto, &QtEncryptDecrypt::encryptionFinished, this,
[=](bool success, const QStringList &encryptedParts,
const QString &error) {
QMetaObject::invokeMethod(this, [=]() {
if (!success) {
emit errorOccurred(error);
} else {
// 保存元数据
QJsonObject metaData;
metaData["key"] = encryptedAesKey;
metaData["iv"] = aesIV;
metaData["original_file"] = QFileInfo(filePath).fileName();
metaData["total_parts"] = encryptedParts.size();
QFile metaFile(outputFilePath + ".meta");
if (!metaFile.open(QIODevice::WriteOnly)) {
emit errorOccurred(tr("Failed to save metadata"));
return;
}
metaFile.write(QJsonDocument(metaData).toJson());
metaFile.close();
m_operating = false;
// 发送加密完成信号
emit fileEncrypted(
true,
tr("File encrypted successfully: %1").arg(outputFilePath));
}
});
}); // 连接加密完成槽函数
// 启动分块加密
m_crypto->encryptFileChunked_AES(filePath, outputFilePath,
QByteArray::fromBase64(aesKey.toLatin1()),
QByteArray::fromBase64(aesIV.toLatin1()));
}
// 解密大文件(分块解密)
void CoreService::decryptLargeFileServer(const QString &metaFilePath,
QString &outPath) {
if (m_operating)
return;
m_operating = true;
if (metaFilePath.isEmpty()) {
emit errorOccurred(tr("Metadata file path cannot be empty"));
return;
}
// 读取元数据
QFile metaFile(metaFilePath);
if (!metaFile.open(QIODevice::ReadOnly)) {
emit errorOccurred(tr("Failed to read metadata"));
return;
}
QJsonDocument doc = QJsonDocument::fromJson(metaFile.readAll());
metaFile.close();
if (doc.isNull()) {
emit errorOccurred(tr("Invalid metadata format"));
return;
}
QJsonObject obj = doc.object();
QString encryptedKey = obj["key"].toString();
QString aesIV = obj["iv"].toString();
QString originalFileName = obj["original_file"].toString();
int totalParts = obj.value("total_parts").toInt();
// 获取当前用户的私钥
QString privateKey, error;
if (!m_keyManager->extractPrivateKey(privateKey, error)) {
emit errorOccurred(error);
return;
}
// 使用私钥解密 AES 密钥
QString aesKey;
if (!m_crypto->decryptCiphertext_RSA(encryptedKey, privateKey, aesKey,
error)) {
emit errorOccurred(error);
return;
}
// 检查所有分块文件是否存在
// 所有分块文件均和*.meta文件在同一目录下
QFileInfo metaFileInfo(metaFilePath);
QString savePath = metaFileInfo.absolutePath();
QStringList encryptedParts;
for (int i = 1; i <= totalParts; ++i) {
QString partName = savePath + "/" + originalFileName + ".encrypted" +
QString(".part%1").arg(i);
if (!QFile::exists(partName)) {
emit errorOccurred(tr("Missing chunk file: %1").arg(partName));
return;
}
encryptedParts << partName;
}
QString outputFilePath = outPath + "/decrypted_" + originalFileName;
connect(m_crypto, &QtEncryptDecrypt::decryptionProgressChanged, this,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(
this, [=]() { emit decryptionProgress(total, processed); });
}); // 连接进度条槽函数
connect(m_crypto, &QtEncryptDecrypt::decryptionFinished, this,
[=](bool success, const QString &error) {
QMetaObject::invokeMethod(this, [=]() {
if (!success) {
emit errorOccurred(error);
} else {
m_operating = false;
// 发送解密完成信号
emit fileDecrypted(
true,
tr("File decrypted successfully: %1").arg(outputFilePath));
}
});
}); // 连接解密完成槽函数
m_crypto->decryptFileChunked_AES(
outputFilePath, QByteArray::fromBase64(aesKey.toLatin1()),
QByteArray::fromBase64(aesIV.toLatin1()), encryptedParts);
}
decrypttask.cpp
#include "decrypttask.h"
#include <QFileInfo>
#define MEMORY_MAP_SIZE (256 * 1024 * 1024) // 256MB内存映射块
#define AES_BLOCK_SIZE 16
DecryptTask::DecryptTask(const QString &inputPath, int partIndex,
const QByteArray &key, const QByteArray &iv,
QVector<QByteArray> &outputBuffers,
QMutex &bufferMutex, QAtomicInt &cancelFlag,
QObject *parent)
: QObject(parent), m_inputPath(inputPath), m_partIndex(partIndex),
m_key(key), m_iv(iv), m_outputBuffers(outputBuffers),
m_bufferMutex(bufferMutex), m_cancelFlag(cancelFlag) {
setAutoDelete(false); // 需要手动管理对象生命周期
QFileInfo fi(inputPath);
m_totalBytes = fi.size();
}
void DecryptTask::run() {
QFile inFile(m_inputPath);
if (!inFile.open(QIODevice::ReadOnly)) {
emit errorOccurred(tr("Unable to open encrypted block file: %1").arg(m_inputPath));
emit completed(m_partIndex, false);
return;
}
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx || !EVP_DecryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(m_key.constData()),
reinterpret_cast<const unsigned char *>(m_iv.constData()))) {
EVP_CIPHER_CTX_free(ctx);
emit errorOccurred(tr("Decryption initialization failed"));
emit completed(m_partIndex, false);
return;
}
QByteArray decryptedData;
bool success = true;
qint64 remaining = inFile.size();
qint64 mapOffset = 0;
m_timer.start();
while (remaining > 0 && !m_cancelFlag.loadAcquire()) {
// 处理暂停状态
{
QMutexLocker lock(&m_stateMutex);
if (m_state == Paused) {
m_pauseCondition.wait(&m_stateMutex);
}
if (m_state == Stopped)
break;
}
// 内存映射处理
const qint64 mapSize = qMin(remaining, MEMORY_MAP_SIZE);
uchar *mapPtr = inFile.map(mapOffset, mapSize);
if (!mapPtr) {
success = false;
break;
}
// 处理映射数据
if (!processMappedData(mapPtr, mapSize, ctx, decryptedData)) {
success = false;
break;
}
// 更新进度
m_processedBytes += mapSize;
mapOffset += mapSize;
remaining -= mapSize;
emit progressUpdated(m_partIndex, mapSize);
inFile.unmap(mapPtr);
}
// 处理最终块
if (success && !m_cancelFlag.loadAcquire()) {
unsigned char finalBuf[AES_BLOCK_SIZE];
int finalLen = 0;
success = EVP_DecryptFinal_ex(ctx, finalBuf, &finalLen);
if (success && finalLen > 0) {
decryptedData.append(reinterpret_cast<char *>(finalBuf), finalLen);
}
}
// 存储解密数据
if (success && !m_cancelFlag.loadAcquire()) {
QMutexLocker lock(&m_bufferMutex);
if (m_partIndex >= m_outputBuffers.size()) {
m_outputBuffers.resize(m_partIndex + 1);
}
m_outputBuffers[m_partIndex] = decryptedData;
}
// 清理资源
EVP_CIPHER_CTX_free(ctx);
inFile.close();
if (!success || m_cancelFlag.loadAcquire()) {
//清除临时文件
emit completed(m_partIndex, false);
} else {
m_state = Completed;
emit completed(m_partIndex, true);
}
}
bool DecryptTask::processMappedData(uchar *data, qint64 size,
EVP_CIPHER_CTX *ctx, QByteArray &buffer) {
const int outSize = size + AES_BLOCK_SIZE;
QScopedArrayPointer<unsigned char> outBuf(new unsigned char[outSize]);
int outLen = 0;
if (1 != EVP_DecryptUpdate(ctx, outBuf.data(), &outLen, data, size)) {
emit errorOccurred(tr("Decryption process error"));
return false;
}
buffer.append(reinterpret_cast<char *>(outBuf.data()), outLen);
return true;
}
// 状态控制方法
void DecryptTask::pause() {
QMutexLocker lock(&m_stateMutex);
m_state = Paused;
}
void DecryptTask::resume() {
QMutexLocker lock(&m_stateMutex);
if (m_state == Paused) {
m_state = Running;
m_pauseCondition.wakeAll();
}
}
void DecryptTask::cancel() {
QMutexLocker lock(&m_stateMutex);
m_state = Stopped;
m_pauseCondition.wakeAll();
}
// 状态查询方法
DecryptTask::State DecryptTask::state() const {
QMutexLocker lock(&m_stateMutex);
return m_state;
}
qint64 DecryptTask::processedBytes() const { return m_processedBytes; }
qint64 DecryptTask::totalBytes() const { return m_totalBytes; }
double DecryptTask::speed() const {
return m_timer.elapsed() > 0 ? (m_processedBytes / 1024.0 / 1024.0) /
(m_timer.elapsed() / 1000.0)
: 0.0;
}
int DecryptTask::partIndex() const { return m_partIndex; }
encryptiondecryptionmanager.cpp
#include "encryptiondecryptionmanager.h"
#include "asyncdecrypttask.h"
#include "asyncencrypttask.h"
EncryptionDecryptionManager::EncryptionDecryptionManager(QObject *parent)
: QObject(parent) {
m_threadPool.setMaxThreadCount(QThread::idealThreadCount());
}
void EncryptionDecryptionManager::encryptFile(const QString &inputPath,
const QString &outputPath,
const QByteArray &key,
const QByteArray &iv) {
m_cancelFlag.storeRelease(false);
m_processedBytes = 0;
// 获取文件大小
QFile file(inputPath);
if (!file.open(QIODevice::ReadOnly)) {
emit encryptionOperationFinished(false, "Unable to open source file");
return;
}
m_totalBytes = file.size();
file.close();
// 创建并提交任务
AsyncEncryptTask *task = new AsyncEncryptTask(
inputPath, outputPath, 0, m_totalBytes, key, iv, m_cancelFlag);
task->setAutoDelete(true);
connect(task, &AsyncEncryptTask::progressChanged, [this](qint64 bytes) {
m_processedBytes += bytes;
emit progressChanged(m_totalBytes, m_processedBytes);
});
connect(task, &AsyncEncryptTask::finished,
[this](bool success, const QString &error) {
emit encryptionOperationFinished(success, error);
});
m_threadPool.start(task);
}
void EncryptionDecryptionManager::decryptFile(const QString &inputPath,
const QString &outputPath,
const QByteArray &key,
const QByteArray &iv) {
m_cancelFlag.storeRelease(false);
m_processedBytes = 0;
// 获取加密文件大小
QFile file(inputPath);
if (!file.open(QIODevice::ReadOnly)) {
emit decryptionOperationFinished(false, "Unable to open encrypted file");
return;
}
m_totalBytes = file.size();
file.close();
// 创建并提交解密任务
AsyncDecryptTask *task =
new AsyncDecryptTask(inputPath, outputPath, key, iv, m_cancelFlag);
task->setAutoDelete(true);
connect(task, &AsyncDecryptTask::progressChanged, [this](qint64 bytes) {
m_processedBytes += bytes;
emit progressChanged(m_totalBytes, m_processedBytes);
});
connect(task, &AsyncDecryptTask::finished,
[this](bool success, const QString &error) {
emit decryptionOperationFinished(success, error);
});
m_threadPool.start(task);
}
void EncryptionDecryptionManager::cancelAll() {
m_cancelFlag.storeRelease(true);
m_threadPool.clear();
m_threadPool.waitForDone();
}
encrypttask.cpp
#include "encrypttask.h"
#include <QFile>
#include <QFileInfo>
#include <openssl/evp.h>
constexpr auto AES_BLOCK_SIZE = 16;
constexpr auto MEMORY_MAP_SIZE = (256 * 1024 * 1024); // 256MB内存映射块
EncryptTask::EncryptTask(const QString &inputPath, const QString &outputPath,
qint64 readOffset, qint64 chunkSize,
const QByteArray &key, const QByteArray &iv,
QAtomicInt &cancelFlag, QObject *parent)
: QObject(parent), m_inputPath(inputPath), m_outputPath(outputPath),
m_readOffset(readOffset), m_chunkSize(chunkSize), m_key(key), m_iv(iv),
m_cancelFlag(cancelFlag) {
setAutoDelete(false); // 需要手动管理对象生命周期
}
void EncryptTask::run() {
QFile inFile(m_inputPath);
if (!inFile.open(QIODevice::ReadOnly)) {
emit errorOccurred(tr("Unable to open input file"));
emit completed(false);
return;
}
QFile outFile(m_outputPath);
if (!outFile.open(QIODevice::WriteOnly)) {
emit errorOccurred(tr("Unable to create output file"));
emit completed(false);
return;
}
// 初始化加密器
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (m_key.size() != 32 || m_iv.size() != 16) {
EVP_CIPHER_CTX_free(ctx);
emit errorOccurred(tr("Key or IV length is incorrect"));
emit completed(false);
return;
}
if (!ctx || !EVP_EncryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(m_key.constData()),
reinterpret_cast<const unsigned char *>(m_iv.constData()))) {
EVP_CIPHER_CTX_free(ctx);
emit errorOccurred(tr("Encryption initialization failed"));
emit completed(false);
return;
}
qint64 remaining = m_chunkSize;
qint64 mapOffset = m_readOffset;
bool success = true;
m_timer.start();
while (remaining > 0 && !m_cancelFlag.loadAcquire()) {
// 处理暂停状态
{
QMutexLocker lock(&m_stateMutex);
if (m_state == Paused) {
m_pauseCondition.wait(&m_stateMutex);
}
if (m_state == Stopped)
break;
}
// 内存映射处理
const qint64 mapSize = qMin(remaining, MEMORY_MAP_SIZE);
uchar *mapPtr = inFile.map(mapOffset, mapSize);
if (!mapPtr) {
success = false;
break;
}
// 加密处理
QVector<unsigned char> outBuf(mapSize + AES_BLOCK_SIZE);
int outLen = 0;
if (!EVP_EncryptUpdate(ctx, outBuf.data(), &outLen, mapPtr, mapSize)) {
success = false;
break;
}
// 写入加密数据
if (outFile.write(reinterpret_cast<char *>(outBuf.data()), outLen) != outLen) {
success = false;
break;
}
// 更新进度
m_processedBytes += mapSize;
mapOffset += mapSize;
remaining -= mapSize;
emit progressUpdated(mapSize);
inFile.unmap(mapPtr);
}
// 处理最终块
if (success && !m_cancelFlag.loadAcquire()) {
unsigned char finalBuf[AES_BLOCK_SIZE];
int finalLen = 0;
success = EVP_EncryptFinal_ex(ctx, finalBuf, &finalLen);
if (success && finalLen > 0) {
success = (outFile.write(reinterpret_cast<char*>(finalBuf), finalLen) == finalLen);
}
}
// 清理资源
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
if (!success || m_cancelFlag.loadAcquire()) {
outFile.remove();
emit completed(false);
} else {
m_state = Completed;
emit completed(true);
}
}
// 状态控制方法
void EncryptTask::pause() {
QMutexLocker lock(&m_stateMutex);
m_state = Paused;
}
void EncryptTask::resume() {
QMutexLocker lock(&m_stateMutex);
if (m_state == Paused) {
m_state = Running;
m_pauseCondition.wakeAll();
}
}
void EncryptTask::cancel() {
QMutexLocker lock(&m_stateMutex);
m_state = Stopped;
m_pauseCondition.wakeAll();
}
// 状态查询方法
EncryptTask::State EncryptTask::state() const {
QMutexLocker lock(&m_stateMutex);
return m_state;
}
qint64 EncryptTask::processedBytes() const { return m_processedBytes; }
qint64 EncryptTask::totalBytes() const { return m_chunkSize; }
double EncryptTask::speed() const {
return m_timer.elapsed() > 0 ? (m_processedBytes / 1024.0 / 1024.0) /
(m_timer.elapsed() / 1000.0)
: 0.0;
}
functionwidget.cpp
#include "functionwidget.h"
FunctionWidget::FunctionWidget(QWidget *parent)
: QWidget(parent)
{
initFunctionWidget();
}
void FunctionWidget::initFunctionWidget()
{
// TODO: add function widgets here
comBoxUserList = new QComboBox(this);
browserUserAndKeyInfo=new QTextBrowser(this);
browserUserAndKeyInfo->setReadOnly(true);
browserUserAndKeyInfo->setMinimumSize(120, 120);
btnEncrypt = new QPushButton("Encrypt", this);
btnEncrypt->setMinimumSize(80, 30);
btnEncryptBlockFile = new QPushButton("Encrypt Block File", this);
btnEncryptBlockFile->setMinimumSize(80, 30);
btnEncryptFile = new QPushButton("Encrypt File", this);
btnEncryptFile->setMinimumSize(80, 30);
btnDecrypt = new QPushButton("Decrypt", this);
btnDecrypt->setMinimumSize(80, 30);
btnDecryptBlockFile = new QPushButton("Decrypt Block File", this);
btnDecryptBlockFile->setMinimumSize(80, 30);
btnDecryptFile = new QPushButton("Decrypt File", this);
btnDecryptFile->setMinimumSize(80, 30);
btnCopyPlaintext = new QPushButton("Copy Plaintext", this);
btnCopyPlaintext->setMinimumSize(80, 30);
btnCopyCiphertext = new QPushButton("Copy Ciphertext", this);
btnCopyCiphertext->setMinimumSize(120, 30);
btnKeyGenerate = new QPushButton("Key Generate", this);
btnKeyGenerate->setMinimumSize(120, 30);
btnImportKey = new QPushButton("Import User&Key", this);
btnImportKey->setMinimumSize(120, 30);
btnSelectSendUser = new QPushButton("Select Send User", this);
btnSelectSendUser->setMinimumSize(120, 30);
btnOpenWorkspace = new QPushButton("Open Workspace", this);
btnOpenWorkspace->setMinimumSize(120, 30);
// add widgets to layout
mainLayout = new QGridLayout();
mainLayout->addWidget(comBoxUserList, 0, 0, 1, 3);
mainLayout->addWidget(browserUserAndKeyInfo, 1, 0, 1, 3);
mainLayout->addWidget(btnSelectSendUser, 2, 0, 1, 3);
mainLayout->addWidget(btnEncrypt, 3, 0, 1, 1);
mainLayout->addWidget(btnEncryptBlockFile, 3, 1, 1, 1);
mainLayout->addWidget(btnEncryptFile, 3, 2, 1, 1);
mainLayout->addWidget(btnDecrypt, 4, 0, 1, 1);
mainLayout->addWidget(btnDecryptBlockFile, 4, 1, 1, 1);
mainLayout->addWidget(btnDecryptFile, 4, 2, 1, 1);
mainLayout->addWidget(btnCopyPlaintext, 5, 0, 1, 1);
mainLayout->addWidget(btnCopyCiphertext, 5, 1, 1, 1);
mainLayout->addWidget(btnKeyGenerate, 6, 0, 1, 1);
mainLayout->addWidget(btnImportKey, 6, 1, 1, 1);
mainLayout->addWidget(btnOpenWorkspace, 7, 0, 1, 3);
// set layout
this->setLayout(mainLayout);
}
FunctionWidget::~FunctionWidget()
{
// TODO: delete function widgets here
if (comBoxUserList!= nullptr) {
delete comBoxUserList;
comBoxUserList = nullptr;
}
if (browserUserAndKeyInfo!= nullptr) {
delete browserUserAndKeyInfo;
browserUserAndKeyInfo = nullptr;
}
if (btnEncrypt!= nullptr) {
delete btnEncrypt;
btnEncrypt = nullptr;
}
if (btnDecrypt!= nullptr) {
delete btnDecrypt;
btnDecrypt = nullptr;
}
if (btnCopyPlaintext!= nullptr) {
delete btnCopyPlaintext;
btnCopyPlaintext = nullptr;
}
if (btnCopyCiphertext!= nullptr) {
delete btnCopyCiphertext;
btnCopyCiphertext = nullptr;
}
if (btnKeyGenerate!= nullptr) {
delete btnKeyGenerate;
btnKeyGenerate = nullptr;
}
}
keymanager.cpp
#include "keymanager.h"
KeyManager::KeyManager(QObject *parent)
: QObject(parent)
{
initStorage();
// 创建加解密对象
QtEncryptDecrypt m_crypto=new QtEncryptDecrypt(this);
}
bool KeyManager::generateUserKeys(const QString& username, QString& errorMsg, QString& outFilePath)
{
// 清除参数的值
errorMsg.clear();
outFilePath.clear();
// 检查用户名有效性
if (username.isEmpty() || m_users.contains(username)) {
errorMsg = "Invalid username or username already exists";
return false;
}
// 生成RSA密钥对
QString publicKey, privateKey;
if (!m_crypto->generateRSAKeyPair(publicKey, privateKey, errorMsg)) {
errorMsg = errorMsg + "Failed to generate key pair";
return false;
}
// 保存私钥到安全位置(仅供当前用户使用)
QString privateKeyPath = getKeyStoragePath() + "/" + username + ".private";
{
QFile privateFile(privateKeyPath);
if (privateFile.open(QIODevice::WriteOnly)) {
QTextStream out(&privateFile);
out << privateKey;
privateFile.close();
} else {
errorMsg = "Failed to open private key file for writing";
return false;
}
}
// 构建用户信息
UserKeyInfo info;
info.username = username;
info.rsaPublicKey = publicKey;
// 保存密钥包
if (!saveKeyPackage(info)) {
errorMsg = "Failed to save key package";
return false;
}
// 输出密钥文件路径
if (outFilePath.isEmpty()) {
outFilePath = getKeyStoragePath() + "/" + username + ".pubkey";
}
// 保存当前用户
m_users.insert(username, info);
// 设置当前用户
m_currentUser = username;
// 通知UI更新
emit userKeysUpdated();
return true;
}
bool KeyManager::importKeyFile(const QString& filePath)
{
// 读取文件内容
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
// 解析JSON
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
if (doc.isNull())
return false;
QJsonObject json = doc.object();
UserKeyInfo info;
info.username = json["username"].toString();
info.rsaPublicKey = json["rsaPublicKey"].toString();
// 复制到本地存储
QString destPath = getKeyStoragePath() + "/" + info.username + ".pubkey";
if (QFile::exists(destPath)) {
return false; // 已存在
}
if (!QFile::copy(filePath, destPath)) {
return false;
}
m_users.insert(info.username, info);
return true;
}
QList<UserKeyInfo> KeyManager::getAvailableUsers() const
{
return m_users.values();
}
QString KeyManager::getKeyStoragePath()
{
return QCoreApplication::applicationDirPath() + "/KeyManageSystem";
}
bool KeyManager::extractPrivateKey(QString& privateKey, QString& errorMsg)
{
// 清除参数的值
errorMsg.clear();
// 读取当前用户的私钥文件
QString privateKeyPath = getKeyStoragePath() + "/" + m_currentUser + ".private";
QFile privateFile(privateKeyPath);
if (privateFile.open(QIODevice::ReadOnly)) {
QTextStream in(&privateFile);
privateKey = in.readAll();
privateFile.close();
return true;
} else {
errorMsg = "Failed to open private key file for reading";
privateKey.clear();
return false;
}
}
bool KeyManager::selectCurrentUserPrivateKey(QString filename,QString& errorMsg)
{
// 清除参数的值
errorMsg.clear();
// 读取当前用户的私钥文件
QString privateKeyFile = filename;
if (privateKeyFile.isEmpty()) {
errorMsg = "Failed to select private key file";
return false;
} else {
QFile privateFile(privateKeyFile);
if (privateFile.open(QIODevice::ReadOnly)) {
QTextStream in(&privateFile);
privateFile.close();
// 设置当前用户
m_currentUser = QFileInfo(privateKeyFile).baseName();
emit currentUserChanged();
return true;
} else {
errorMsg = "Failed to open private key file for reading";
return false;
}
}
}
bool KeyManager::initStorage()
{
QDir dir(getKeyStoragePath());
if (!dir.exists()) {
return dir.mkpath(".");
}
return true;
}
bool KeyManager::saveKeyPackage(const UserKeyInfo& info)
{
QJsonObject json;
json["username"] = info.username;
json["rsaPublicKey"] = info.rsaPublicKey;
QFile file(getKeyStoragePath() + "/" + info.username + ".pubkey");
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "Failed to open file for writing";
return false;
}
file.write(QJsonDocument(json).toJson());
return true;
}
bool KeyManager::setDefaultCurrentUser()
{
QDir dir(getKeyStoragePath());
QStringList filters { "*.private" };
QFileInfoList files = dir.entryInfoList(filters, QDir::Files);
for (const QFileInfo& fileInfo : files) {
// 找到第一个私钥文件作为默认用户
QString username = fileInfo.baseName().left(fileInfo.baseName().lastIndexOf('.'));
if (m_users.contains(username)) {
m_currentUser = username;
return true;
}
}
return false;
}
void KeyManager::loadLocalKeys()
{
m_users.clear();
QDir dir(getKeyStoragePath());
QStringList filters { "*.pubkey" };
QFileInfoList files = dir.entryInfoList(filters, QDir::Files);
for (const QFileInfo& fileInfo : files) {
QFile file(fileInfo.absoluteFilePath());
if (!file.open(QIODevice::ReadOnly)) {
continue;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
if (doc.isNull()) {
continue;
}
QJsonObject json = doc.object();
UserKeyInfo user;
user.username = json["username"].toString();
user.rsaPublicKey = json["rsaPublicKey"].toString();
if (user.username.isEmpty() || user.rsaPublicKey.isEmpty()) {
continue;
}
m_users.insert(user.username, user);
}
}
KeyManager::~KeyManager()
{
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <openssl/ssl.h>
// 主函数
int main(int argc, char *argv[]) {
// 初始化 OpenSSL
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
// 启动 Qt 应用
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
// 初始化界面
initUIAndSource();
// 初始化数据
initData();
// 连接信号槽
initConnect();
// 初始化菜单栏
initMenuBar();
// 初始化工具栏
initToolBar();
// 初始化状态栏
initStatusBar();
}
MainWindow::~MainWindow() {
delete ui;
if (textWidget != nullptr) {
delete textWidget;
textWidget = nullptr;
}
if (functionWidget != nullptr) {
delete functionWidget;
functionWidget = nullptr;
}
if (gridLayout != nullptr) {
delete gridLayout;
gridLayout = nullptr;
}
if (centralWidget != nullptr) {
delete centralWidget;
centralWidget = nullptr;
}
if (m_coreService != nullptr) {
delete m_coreService;
m_coreService = nullptr;
}
}
// 初始化UI和资源
void MainWindow::initUIAndSource() {
// 设置窗口标题
this->setWindowTitle("Cipher Client");
// 设置中心窗口
centralWidget = new QWidget(this);
this->setCentralWidget(centralWidget);
centralWidget->setEnabled(true);
centralWidget->setMinimumSize(960, 540);
this->setMinimumSize(centralWidget->minimumSize().width(),
centralWidget->minimumSize().height() + 42);
// 文本区域
textWidget = new TextWidget(centralWidget);
// 功能区域
functionWidget = new FunctionWidget(centralWidget);
// 布局管理器
gridLayout = new QGridLayout(centralWidget);
// 左边放文本区域,占据0.618成窗口
gridLayout->addWidget(textWidget, 0, 0);
gridLayout->setColumnStretch(0, 6.18); // 设置第一列的拉伸因子为6.18
// 右边放功能区域,占据0.382成窗口
gridLayout->addWidget(functionWidget, 0, 1);
gridLayout->setColumnStretch(1, 3.82); // 设置第二列的拉伸因子为1-6.18=3.82
centralWidget->setLayout(gridLayout);
// init Server
m_coreService = new CoreService();
}
void MainWindow::initData() {
// 刷新用户数据库
refreshUserList();
// 设置默认行为的当前用户
m_coreService->m_keyManager->setDefaultCurrentUser();
// 显示当前用户
browerConstText += tr("Current Sender (User): ") +
m_coreService->m_keyManager->m_currentUser + "\n";
functionWidget->browserUserAndKeyInfo->setText(browerConstText);
}
void MainWindow::initConnect() {
// 连接信号槽
connect(functionWidget->btnEncrypt, &QPushButton::clicked, this,
&MainWindow::onEncryptBtn);
connect(functionWidget->btnDecrypt, &QPushButton::clicked, this,
&MainWindow::onDecryptBtn);
connect(functionWidget->btnKeyGenerate, &QPushButton::clicked, this,
&MainWindow::onGenerateKeys);
connect(functionWidget->btnImportKey, &QPushButton::clicked, this,
&MainWindow::onImportKey);
connect(m_coreService->m_keyManager, &KeyManager::userKeysUpdated, this,
&MainWindow::refreshUserList);
connect(functionWidget->btnCopyPlaintext, &QPushButton::clicked, this,
&MainWindow::onCopyPlainTextToClipboard);
connect(functionWidget->btnCopyCiphertext, &QPushButton::clicked, this,
&MainWindow::onCopyCipherTextToClipboard);
connect(functionWidget->btnSelectSendUser, &QPushButton::clicked, this,
&MainWindow::onSelectSendUser);
connect(functionWidget->btnOpenWorkspace, &QPushButton::clicked, this,
&MainWindow::onOpenWorkspace);
connect(functionWidget->btnEncryptBlockFile, &QPushButton::clicked, this,
&MainWindow::onEncryptClickedAsyncBlockFile);
connect(functionWidget->btnDecryptBlockFile, &QPushButton::clicked, this,
&MainWindow::onDecryptClickedAsyncBlockFile);
connect(functionWidget->btnEncryptFile, &QPushButton::clicked, this,
&MainWindow::onEncryptClickedAsyncFile);
connect(functionWidget->btnDecryptFile, &QPushButton::clicked, this,
&MainWindow::onDecryptClickedAsyncFile);
// 连接错误收集器
connect(m_coreService, &CoreService::errorOccurred, this,
[=](const QString &error) {
QMessageBox::warning(this, tr("Error"),
tr(error.toStdString().c_str()));
});
}
void MainWindow::initMenuBar() {
// 菜单栏
QMenuBar *menuBar = new QMenuBar(this);
this->setMenuBar(menuBar);
// 固定在上方不可移动
menuBar->setNativeMenuBar(false);
/*文件菜单*/
QMenu *fileMenu = menuBar->addMenu(tr("File"));
// 打开工作区
QAction *openWorkspaceAction = new QAction(tr("Open Workspace"), this);
fileMenu->addAction(openWorkspaceAction);
connect(openWorkspaceAction, &QAction::triggered, this,
&MainWindow::onOpenWorkspace);
// 退出
QAction *quitAction = new QAction(tr("Quit"), this);
fileMenu->addAction(quitAction);
connect(quitAction, &QAction::triggered, this, &QMainWindow::close);
/*密钥管理菜单*/
QMenu *keyManagerMenu = menuBar->addMenu(tr("Key Manager"));
// 刷新用户列表
QAction *refreshUserListAction = new QAction(tr("Refresh User List"), this);
keyManagerMenu->addAction(refreshUserListAction);
connect(refreshUserListAction, &QAction::triggered, this,
&MainWindow::refreshUserList);
// 导入密钥
QAction *importKeyAction = new QAction(tr("Import Key"), this);
keyManagerMenu->addAction(importKeyAction);
connect(importKeyAction, &QAction::triggered, this, &MainWindow::onImportKey);
// 生成密钥
QAction *generateKeyAction = new QAction(tr("Generate Key"), this);
keyManagerMenu->addAction(generateKeyAction);
connect(generateKeyAction, &QAction::triggered, this,
&MainWindow::onGenerateKeys);
// 设置默认用户
QAction *setDefaultUserAction = new QAction(tr("Set Default User"), this);
keyManagerMenu->addAction(setDefaultUserAction);
connect(setDefaultUserAction, &QAction::triggered,
m_coreService->m_keyManager, &KeyManager::setDefaultCurrentUser);
/*帮助菜单*/
QMenu *helpMenu = menuBar->addMenu(tr("Help"));
// 关于
QAction *aboutAction = new QAction(tr("About"), this);
helpMenu->addAction(aboutAction);
connect(aboutAction, &QAction::triggered, this, &MainWindow::onAbout);
}
void MainWindow::initToolBar() {}
void MainWindow::initStatusBar() {
// 状态栏
QStatusBar *statusBar = new QStatusBar(this);
// 初始化所有标签(6个状态)
m_userLabel = new QLabel(this);
m_plainTextLenLabel = new QLabel(this);
m_cipherTextLenLabel = new QLabel(this);
m_timeLabel = new QLabel(this);
m_taskStatusLabel = new QLabel(tr("System: Ready"), this);
m_permanentMsgLabel = new QLabel(tr("Welcome"), this);
// 布局规则:addPermanentWidget从左向右排列
statusBar->addWidget(m_userLabel); // 左侧第1个
statusBar->addPermanentWidget(m_plainTextLenLabel); // 第2个
statusBar->addPermanentWidget(m_cipherTextLenLabel); // 第3个
statusBar->addPermanentWidget(m_timeLabel); // 第4个
statusBar->addPermanentWidget(m_taskStatusLabel); // 第5个
statusBar->addPermanentWidget(m_permanentMsgLabel); // 最右侧第6个状态
this->setStatusBar(statusBar);
// 初始状态
m_userLabel->setText(tr("Current User: ") +
m_coreService->m_keyManager->m_currentUser);
m_plainTextLenLabel->setText(tr("Plain Text: 0 c"));
m_cipherTextLenLabel->setText(tr("Cipher Text: 0 c"));
m_timeLabel->setText(tr("Time: 00:00:00"));
// 当前用户显示(使用已有标签更新内容)
connect(m_coreService->m_keyManager, &KeyManager::currentUserChanged, this,
[=]() {
m_userLabel->setText(tr("Current User: ") +
m_coreService->m_keyManager->m_currentUser);
});
// 明文框字数统计
connect(textWidget->plainTextEdit, &QTextEdit::textChanged, this, [=]() {
int len = textWidget->plainTextEdit->toPlainText().length();
m_plainTextLenLabel->setText(tr("Plain Text: %1 c").arg(len));
});
// 密文框字数统计
connect(textWidget->cipherTextEdit, &QTextEdit::textChanged, this, [=]() {
int len = textWidget->cipherTextEdit->toPlainText().length();
m_cipherTextLenLabel->setText(tr("Cipher Text: %1 c").arg(len));
});
}
void MainWindow::onEncryptBtn() {
// 1. 获取明文
QString plainText = textWidget->plainTextEdit->toPlainText();
if (plainText.isEmpty()) {
QMessageBox::warning(this, tr("Error"), tr("Please input plain text"));
return;
}
connect(m_coreService, &CoreService::textEncrypted, this,
[=](const QString &cipherText) {
// 显示json形式的密文
textWidget->cipherTextEdit->setPlainText(cipherText);
});
m_coreService->encryptTextServer(
plainText, functionWidget->comBoxUserList->currentText());
}
void MainWindow::onEncryptClickedAsyncBlockFile() {
// 1. 选择源文件
QString sourcePath =
QFileDialog::getOpenFileName(this, tr("Select File to Encrypt"),
QDir::homePath(), tr("All Files (*.*)"));
if (sourcePath.isEmpty())
return;
// 2.选择保存路径
QFileInfo srcInfo(sourcePath);
QString saveFolderPath = QFileDialog::getExistingDirectory(
this, tr("Select Save Directory"), srcInfo.absolutePath());
if (saveFolderPath.isEmpty())
return;
// 连接进度条
m_progressDialog = new QProgressDialog("encrypting...", "cancel", 0, 100,
this); // 创建进度条对话框
m_progressDialog->setFixedSize(300, 100);
m_progressDialog->setWindowModality(Qt::NonModal); // 非模态窗口
m_progressDialog->show();
connect(m_progressDialog, &QProgressDialog::canceled, m_coreService->m_crypto,
&QtEncryptDecrypt::cancelEncryption); // 连接取消按钮槽函数
connect(m_coreService, &CoreService::encryptionProgress, this,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->setMaximum(total);
m_progressDialog->setValue(processed);
maxProgressValue = total;
currentProgressValue = processed;
m_progressDialog->setLabelText(
QString("encrypting... %1%")
.arg(static_cast<double>(processed) / total * 100));
});
}); // 连接进度条槽函数
disconnect(m_coreService, &CoreService::fileEncrypted, this,
nullptr); // 断开加密完成槽函数
connect(m_coreService, &CoreService::fileEncrypted, this,
[=](bool success, QString message) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
if (success) {
// 8. 显示结果
QMessageBox::information(this, tr("Success"), message);
// 9. 询问是否打开目录
auto reply = QMessageBox::question(
this, tr("Open Folder"),
tr("Do you want to open the destination folder?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
QDesktopServices::openUrl(
QUrl::fromLocalFile(saveFolderPath));
}
} else {
QMessageBox::warning(this, tr("Error"), message);
}
});
}); // 连接关闭进度条槽函数
// 6. 执行分块加密
m_coreService->encryptLargeFileServer(
sourcePath, saveFolderPath,
functionWidget->comBoxUserList->currentText());
}
void MainWindow::onDecryptBtn() {
// 1. 获取密文
QString cipherText = textWidget->cipherTextEdit->toPlainText();
if (cipherText.isEmpty()) {
QMessageBox::warning(this, tr("Error"), tr("Please input cipher text"));
return;
}
connect(m_coreService, &CoreService::textDecrypted, this,
[=](const QString &plainText) {
// 显示明文
textWidget->plainTextEdit->setPlainText(plainText);
});
m_coreService->decryptTextServer(cipherText);
}
void MainWindow::onDecryptClickedAsyncBlockFile() {
// 1. 选择元数据*.meta文件的文件路径
QString metaFilePath = QFileDialog::getOpenFileName(
this, tr("Select Encrypted File Meta Data"), QDir::homePath(),
tr("Encrypted File Meta Data (*.meta)"));
if (metaFilePath.isEmpty())
return;
// 2. 选择保存路径
QString saveFolderPath =
QFileDialog::getExistingDirectory(this, tr("Select Save Directory"),
QFileInfo(metaFilePath).absolutePath());
if (saveFolderPath.isEmpty())
return;
// 连接进度条
m_progressDialog = new QProgressDialog("decrypting...", "cancel", 0, 100,
this); // 创建进度条对话框
m_progressDialog->setFixedSize(300, 100);
// 非模态窗口
m_progressDialog->setWindowModality(Qt::NonModal);
connect(m_progressDialog, &QProgressDialog::canceled, m_coreService->m_crypto,
&QtEncryptDecrypt::cancelDecryption); // 连接取消按钮槽函数
connect(m_coreService, &CoreService::decryptionProgress, this,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->setMaximum(total);
m_progressDialog->setValue(processed);
maxProgressValue = total;
currentProgressValue = processed;
m_progressDialog->setLabelText(
QString("decrypting... %1%")
.arg(static_cast<double>(processed) / total * 100));
});
m_progressDialog->show();
}); // 连接进度条槽函数
disconnect(m_coreService, &CoreService::fileDecrypted, this,
nullptr); // 断开解密完成槽函数
connect(m_coreService, &CoreService::fileDecrypted, this,
[=](bool success, QString message) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
if (success) {
// 8. 显示结果
QMessageBox::information(this, tr("Success"), message);
// 9. 询问是否打开目录
auto reply = QMessageBox::question(
this, tr("Open Folder"),
tr("Do you want to open the destination folder?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
QDesktopServices::openUrl(QUrl::fromLocalFile(
QFileInfo(saveFolderPath).absolutePath()));
}
} else {
QMessageBox::warning(this, tr("Error"), message);
}
});
}); // 连接关闭进度条槽函数
// 6. 执行分块解密
m_coreService->decryptLargeFileServer(metaFilePath, saveFolderPath);
}
void MainWindow::onGenerateKeys() {
bool ok;
QString username = QInputDialog::getText(
this, tr("New User"), tr("Username:"), QLineEdit::Normal, "", &ok);
if (!ok || username.isEmpty()) {
return;
}
// 生成密钥,用户及保存
QString errorMsg;
QString savedPath;
if (m_coreService->m_keyManager->generateUserKeys(username, errorMsg,
savedPath)) {
QMessageBox::information(this, tr("Success"),
tr("Keys generated at:\n%1").arg(savedPath));
refreshUserList();
} else {
QMessageBox::warning(this, tr("Error"), errorMsg);
}
}
void MainWindow::onImportKey() {
QString path = QFileDialog::getOpenFileName(this, tr("Select Key File"), "",
tr("Key Files (*.pubkey)"));
if (path.isEmpty()) {
return;
}
if (m_coreService->m_keyManager->importKeyFile(path)) {
refreshUserList();
} else {
QMessageBox::warning(this, tr("Error"), tr("Invalid key file"));
}
}
void MainWindow::refreshUserList() {
functionWidget->comBoxUserList->clear();
// 确保加载最新的本地数据
m_coreService->m_keyManager->loadLocalKeys();
QList<UserKeyInfo> users = m_coreService->m_keyManager->getAvailableUsers();
for (const auto &user : users) {
functionWidget->comBoxUserList->addItem(user.username);
}
if (functionWidget->comBoxUserList->count() == 0) {
functionWidget->comBoxUserList->addItem(tr("No users available"));
functionWidget->comBoxUserList->setEnabled(false);
} else {
functionWidget->comBoxUserList->setEnabled(true);
}
}
void MainWindow::onCopyPlainTextToClipboard() {
if (textWidget->plainTextEdit->toPlainText().isEmpty()) {
return;
}
QApplication::clipboard()->setText(textWidget->plainTextEdit->toPlainText());
}
void MainWindow::onCopyCipherTextToClipboard() {
if (textWidget->cipherTextEdit->toPlainText().isEmpty()) {
return;
}
QApplication::clipboard()->setText(textWidget->cipherTextEdit->toPlainText());
}
void MainWindow::onSelectSendUser() {
QString filename = QFileDialog::getOpenFileName(
this, tr("Select Private Key"),
m_coreService->m_keyManager->getKeyStoragePath(),
tr("All Files (*.private)"));
if (filename.isEmpty()) {
return;
}
QString errorMsg;
if (!m_coreService->m_keyManager->selectCurrentUserPrivateKey(filename,
errorMsg)) {
QMessageBox::warning(this, tr("Error"), errorMsg);
return;
}
browerConstText += tr("Current Sender (User): ") +
m_coreService->m_keyManager->m_currentUser + "\n";
functionWidget->browserUserAndKeyInfo->setText(browerConstText);
}
void MainWindow::onOpenWorkspace() {
// 打开工作区即程序本体所在目录
QString path = QCoreApplication::applicationDirPath();
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
void MainWindow::onAbout() {
const QString aboutText = R"(
Cipher Client
Version: 1.0.3
Copyright (C) 2024 kekezack
All rights reserved.
This software is provided 'as is' and any express or implied
warranties are disclaimed. In no event shall the author be liable for any
damages arising from the use of this software.
For support, please contact:
Email: xzhkekezack@gmail.com
Licensed under the MIT License.
)";
QMessageBox::about(this, tr("About Cipher Client"), aboutText);
}
void MainWindow::onEncryptClickedAsyncFile() {
// 1. 选择源文件
QString sourceFilePath =
QFileDialog::getOpenFileName(this, tr("Select File to Encrypt"),
QDir::homePath(), tr("All Files (*.*)"));
if (sourceFilePath.isEmpty())
return;
// 2. 选择保存路径
QFileInfo srcInfo(sourceFilePath);
QString saveFolderPath = QFileDialog::getExistingDirectory(
this, tr("Select Save Directory"), srcInfo.absolutePath());
if (saveFolderPath.isEmpty())
return;
// 连接进度条
m_progressDialog = new QProgressDialog("encrypting...", "cancel", 0, 100,
this); // 创建进度条对话框
m_progressDialog->setFixedSize(300, 100);
m_progressDialog->setWindowModality(Qt::NonModal); // 非模态窗口
m_progressDialog->show();
connect(m_progressDialog, &QProgressDialog::canceled,
m_coreService->m_cryptoManager,
&EncryptionDecryptionManager::cancelAll); // 连接取消按钮槽函数
connect(m_coreService, &CoreService::encryptionProgress,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->setMaximum(total);
m_progressDialog->setValue(processed);
maxProgressValue = total;
currentProgressValue = processed;
m_progressDialog->setLabelText(
QString("encrypting... %1%")
.arg(static_cast<double>(processed) / total * 100));
});
}); // 连接进度条槽函数
disconnect(m_coreService, &CoreService::fileEncrypted, this,
nullptr); // 断开加密完成槽函数
connect(m_coreService, &CoreService::fileEncrypted, this,
[=](bool success, QString message) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
if (success) {
// 8. 显示结果
QMessageBox::information(this, tr("Success"), message);
// 9. 询问是否打开目录
auto reply = QMessageBox::question(
this, tr("Open Folder"),
tr("Do you want to open the destination folder?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
QDesktopServices::openUrl(
QUrl::fromLocalFile(QFileInfo(srcInfo).absolutePath()));
}
} else {
QMessageBox::warning(this, "error", message);
}
});
}); // 连接完成槽函数
// 6. 执行加密
m_coreService->encryptFileServer(
sourceFilePath, saveFolderPath,
functionWidget->comBoxUserList->currentText());
}
void MainWindow::onDecryptClickedAsyncFile() {
// 1. 选择加密文件}
QString encryptedFilePath = QFileDialog::getOpenFileName(
this, tr("Select Encrypted File"), QDir::homePath(),
tr("Encrypted Files (*.encrypted)"));
if (encryptedFilePath.isEmpty())
return;
// 2. 选择保存路径
QFileInfo srcInfo(encryptedFilePath);
QString savePath = QFileDialog::getExistingDirectory(
this, tr("Select Save Directory"), srcInfo.absolutePath());
if (savePath.isEmpty())
return;
// 连接进度条
m_progressDialog = new QProgressDialog("decrypting...", "cancel", 0, 100,
this); // 创建进度条对话框
m_progressDialog->setFixedSize(300, 100);
m_progressDialog->setWindowModality(Qt::NonModal); // 非模态窗口
m_progressDialog->show();
connect(m_progressDialog, &QProgressDialog::canceled,
m_coreService->m_cryptoManager,
&EncryptionDecryptionManager::cancelAll); // 连接取消按钮槽函数
connect(m_coreService, &CoreService::decryptionProgress,
[this](qint64 total, qint64 processed) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->setMaximum(total);
m_progressDialog->setValue(processed);
maxProgressValue = total;
currentProgressValue = processed;
m_progressDialog->setLabelText(
QString("decrypting... %1%")
.arg(static_cast<double>(processed) / total * 100));
});
}); // 连接进度条槽函数
disconnect(m_coreService, &CoreService::fileDecrypted, this,
nullptr); // 断开解密完成槽函数
connect(m_coreService, &CoreService::fileDecrypted, this,
[=](bool success, QString msg) {
QMetaObject::invokeMethod(m_progressDialog, [=]() {
m_progressDialog->close();
delete m_progressDialog;
m_progressDialog = nullptr;
if (success) {
// 8. 显示结果
QMessageBox::information(this, tr("Success"), msg);
// 9. 询问是否打开目录
auto reply = QMessageBox::question(
this, tr("Open Folder"),
tr("Do you want to open the destination folder?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
QDesktopServices::openUrl(QUrl::fromLocalFile(savePath));
}
} else {
QMessageBox::warning(this, tr("Error"), msg);
}
});
}); // 连接完成槽函数
// 6. 执行解密
m_coreService->decryptFileServer(encryptedFilePath, savePath);
}
paralleldecryptor.cpp
#include "paralleldecryptor.h"
#include "decrypttask.h"
#include <QDir>
#include <QFile>
ParallelDecryptor::ParallelDecryptor(QObject *parent) : QObject(parent) {
m_threadPool.setMaxThreadCount(QThread::idealThreadCount());
}
ParallelDecryptor::~ParallelDecryptor() { cancelAll(); }
void ParallelDecryptor::decryptFile(const QStringList &encryptedParts,
const QString &outputPath,
const QByteArray &key,
const QByteArray &iv) {
// 重置状态
cancelAll();
m_processedBytes = 0;
m_finalOutputPath = outputPath;
// 计算总大小
foreach (const QString &path, encryptedParts) {
m_totalBytes += QFileInfo(path).size();
}
m_totalTimer.start();
// 初始化缓冲区
m_outputBuffers.resize(encryptedParts.size());
// 创建解密任务
for (int i = 0; i < encryptedParts.size(); ++i) {
DecryptTask *task =
new DecryptTask(encryptedParts[i], i, key, iv, m_outputBuffers,
m_bufferMutex, m_cancelFlag, this);
connect(task, &DecryptTask::progressUpdated, this,
&ParallelDecryptor::handleTaskProgress);
connect(task, &DecryptTask::completed, this,
&ParallelDecryptor::handleTaskCompletion);
connect(task, &DecryptTask::errorOccurred, this,
&ParallelDecryptor::errorOccurred);
connect(this, &ParallelDecryptor::errorOccurred, this,
[&](QString message) { m_lastError = message; });
m_tasks.append(task);
m_threadPool.start(task);
}
}
void ParallelDecryptor::handleTaskProgress(int partIndex, qint64 bytes) {
Q_UNUSED(partIndex)
m_processedBytes += bytes;
emit progressChanged(m_totalBytes, m_processedBytes);
}
void ParallelDecryptor::handleTaskCompletion() {
// 检查所有任务是否完成
bool allDone = true;
foreach (DecryptTask *task, m_tasks) {
if (task->state() != DecryptTask::Completed) {
allDone = false;
break;
}
}
if (allDone) {
bool overallSuccess = true;
foreach (DecryptTask *task, m_tasks) {
if (task->state() == DecryptTask::Stopped || !task->processedBytes()) {
overallSuccess = false;
break;
}
}
if (overallSuccess) {
overallSuccess = writeFinalOutput(m_finalOutputPath);
}
emit completed(overallSuccess);
}
}
// 控制方法
void ParallelDecryptor::pauseAll() {
foreach (DecryptTask *task, m_tasks) {
task->pause();
}
}
void ParallelDecryptor::resumeAll() {
foreach (DecryptTask *task, m_tasks) {
task->resume();
}
}
void ParallelDecryptor::cancelAll() {
m_cancelFlag.storeRelease(1);
m_threadPool.clear();
foreach (DecryptTask *task, m_tasks) {
task->cancel();
delete task;
}
m_tasks.clear();
m_outputBuffers.clear();
m_cancelFlag.storeRelease(0);
}
// 状态查询
bool ParallelDecryptor::isRunning() const {
return !m_tasks.isEmpty() && m_threadPool.activeThreadCount() > 0;
}
qint64 ParallelDecryptor::totalProgress() const { return m_processedBytes; }
qint64 ParallelDecryptor::totalBytes() const { return m_totalBytes; }
double ParallelDecryptor::overallSpeed() const {
return m_totalTimer.elapsed() > 0 ? (m_processedBytes / 1024.0 / 1024.0) /
(m_totalTimer.elapsed() / 1000.0)
: 0.0;
}
// 写入最终文件
bool ParallelDecryptor::writeFinalOutput(const QString &path) {
QFile outFile(path);
if (!outFile.open(QIODevice::WriteOnly)) {
emit errorOccurred(tr("无法创建输出文件"));
return false;
}
// 按顺序写入所有分块
for (const QByteArray &data : m_outputBuffers) {
if (data.isEmpty()) {
emit errorOccurred(tr("遇到空解密分块"));
outFile.remove();
return false;
}
if (outFile.write(data) != data.size()) {
emit errorOccurred(tr("文件写入失败"));
outFile.remove();
return false;
}
}
outFile.close();
return true;
}
parallelencryptor.cpp
#include "parallelencryptor.h"
#include "encrypttask.h"
#include <QFile>
#include <QFileInfo>
ParallelEncryptor::ParallelEncryptor(QObject *parent) : QObject(parent) {
m_threadPool.setMaxThreadCount(QThread::idealThreadCount());
}
ParallelEncryptor::~ParallelEncryptor() { cancelAll(); }
void ParallelEncryptor::encryptFile(const QString &inputPath,
const QString &outputBasePath,
const QByteArray &key,
const QByteArray &iv) {
// 重置状态
cancelAll();
m_processedBytes = 0;
m_totalBytes = QFileInfo(inputPath).size();
m_totalTimer.start();
// 分割文件
const qint64 chunkSize = 2LL * 1024 * 1024 * 1024; // 2GB
qint64 remaining = m_totalBytes;
qint64 offset = 0;
int partNumber = 1;
QStringList outputPaths;
while (remaining > 0) {
const qint64 currentChunk = qMin(remaining, chunkSize);
QString outputPath =
QString("%1.part%2").arg(outputBasePath).arg(partNumber++);
EncryptTask *task = new EncryptTask(inputPath, outputPath, offset,
currentChunk, key, iv, m_cancelFlag);
connect(task, &EncryptTask::progressUpdated, this,
&ParallelEncryptor::handleTaskProgress);
connect(task, &EncryptTask::completed, this,
&ParallelEncryptor::handleTaskCompletion);
connect(task, &EncryptTask::errorOccurred, this,
&ParallelEncryptor::errorOccurred);
connect(this, &ParallelEncryptor::errorOccurred, this,
[&](const QString &message) { m_lastError = message; });
m_tasks.append(task);
m_threadPool.start(task);
offset += currentChunk;
remaining -= currentChunk;
}
}
void ParallelEncryptor::handleTaskProgress(qint64 bytes) {
m_processedBytes += bytes;
emit progressChanged(m_totalBytes, m_processedBytes);
}
void ParallelEncryptor::handleTaskCompletion() {
// 检查所有任务是否完成
bool allDone = true;
foreach (EncryptTask *task, m_tasks) {
if (task->state() != EncryptTask::Completed) {
allDone = false;
break;
}
}
if (allDone) {
bool overallSuccess = true;
foreach (EncryptTask *task, m_tasks) {
if (task->state() == EncryptTask::Stopped) {
overallSuccess = false;
break;
}
}
if (overallSuccess) {
foreach (EncryptTask *task, m_tasks) {
m_encryptedParts.append(task->m_outputPath);
}
m_tasks.clear();
emit completed(overallSuccess);
}
}
}
// 控制方法
void ParallelEncryptor::pauseAll() {
foreach (EncryptTask *task, m_tasks) {
task->pause();
}
}
void ParallelEncryptor::resumeAll() {
foreach (EncryptTask *task, m_tasks) {
task->resume();
}
}
void ParallelEncryptor::cancelAll() {
m_cancelFlag.storeRelease(1);
m_threadPool.clear();
foreach (EncryptTask *task, m_tasks) {
task->cancel();
delete task;
}
m_tasks.clear();
m_cancelFlag.storeRelease(0);
}
// 状态查询
bool ParallelEncryptor::isRunning() const {
return !m_tasks.isEmpty() && m_threadPool.activeThreadCount() > 0;
}
qint64 ParallelEncryptor::totalProgress() const { return m_processedBytes; }
double ParallelEncryptor::overallSpeed() const {
return m_totalTimer.elapsed() > 0 ? (m_processedBytes / 1024.0 / 1024.0) /
(m_totalTimer.elapsed() / 1000.0)
: 0.0;
}
qtencryptdecrypt.cpp
#include "qtencryptdecrypt.h"
QtEncryptDecrypt::QtEncryptDecrypt(QObject *parent) : QObject(parent) {}
QtEncryptDecrypt::~QtEncryptDecrypt() {}
bool QtEncryptDecrypt::generateAESKey(QString &keyStr, QString &ivStr,
QString &errMessage) {
// 清空输出参数
keyStr.clear();
ivStr.clear();
errMessage.clear();
// 生成 256 位(32 字节)AES 密钥
unsigned char key[AES_KEY_SIZE_32];
if (RAND_bytes(key, AES_KEY_SIZE_32) != 1) {
errMessage = "generateAESKey: Failed to generate secure random key.";
return false; // 随机数生成失败
}
// 生成 128 位(16 字节)IV
unsigned char iv[AES_BLOCK_SIZE_16];
if (RAND_bytes(iv, AES_BLOCK_SIZE_16) != 1) {
errMessage = "generateAESKey: Failed to generate secure random iv.";
return false; // 随机数生成失败
}
// 将密钥和 IV 转换为 Base64 编码的字符串
QByteArray keyBytes(reinterpret_cast<const char *>(key), AES_KEY_SIZE_32);
QByteArray ivBytes(reinterpret_cast<const char *>(iv), AES_BLOCK_SIZE_16);
keyStr = keyBytes.toBase64();
ivStr = ivBytes.toBase64();
return true;
}
bool QtEncryptDecrypt::encryptPlaintext_AES(const QString &plaintext,
const QString &keyStr,
const QString &ivStr,
QString &ciphertext,
QString &errMessage) {
// 清空输出参数
ciphertext.clear();
errMessage.clear();
// 输入参数检查
if (plaintext.isEmpty() || keyStr.isEmpty() || ivStr.isEmpty()) {
errMessage = "encryptPlaintext_AES: Invalid input parameters.";
return false;
}
// 密钥长度为 32 字节,IV 长度为 16 字节
QByteArray keyBytes = QByteArray::fromBase64(keyStr.toUtf8());
QByteArray ivBytes = QByteArray::fromBase64(ivStr.toUtf8());
// 密钥和 IV 长度检查
if (keyBytes.size() != AES_KEY_SIZE_32 ||
ivBytes.size() != AES_BLOCK_SIZE_16) {
errMessage = "encryptPlaintext_AES: Invalid key or iv size.";
return false;
}
// 创建加密上下文
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
errMessage = "encryptPlaintext_AES: Failed to create cipher context.";
return false;
}
// 初始化加密上下文
if (EVP_EncryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(keyBytes.constData()),
reinterpret_cast<const unsigned char *>(ivBytes.constData())) != 1) {
EVP_CIPHER_CTX_free(ctx);
errMessage = "encryptPlaintext_AES: Failed to initialize cipher context.";
return false;
}
// 明文转换为字节数组
const QByteArray plainArray = plaintext.toUtf8();
const unsigned char *plainTextPtr =
reinterpret_cast<const unsigned char *>(plainArray.constData());
int plainTextLen = plainArray.size();
// 分配足够的缓冲区(明文长度 + 块大小)
std::vector<unsigned char> cipherText(plainTextLen + AES_BLOCK_SIZE_16);
int len = 0, totalLen = 0;
// 加密
if (EVP_EncryptUpdate(ctx, cipherText.data(), &len, plainTextPtr,
plainTextLen) != 1) {
EVP_CIPHER_CTX_free(ctx);
errMessage = "encryptPlaintext_AES: Failed to encrypt plaintext.";
return false;
}
totalLen = len;
// 加密后的数据可能大于明文长度,需要填充
if (EVP_EncryptFinal_ex(ctx, cipherText.data() + len, &len) != 1) {
EVP_CIPHER_CTX_free(ctx);
errMessage = "encryptPlaintext_AES: Failed to finalize encryption.";
return false;
}
totalLen += len;
cipherText.resize(totalLen); // 调整到实际大小
QByteArray cipherBytes(reinterpret_cast<const char *>(cipherText.data()),
totalLen);
ciphertext = QString::fromLatin1(cipherBytes.toHex());
// 释放加密上下文
EVP_CIPHER_CTX_free(ctx);
return true;
}
bool QtEncryptDecrypt::decryptCiphertext_AES(const QString &ciphertext,
const QString &key,
const QString &iv,
QString &plaintext,
QString &errMessage) {
// 清空输出参数
plaintext.clear();
errMessage.clear();
// 输入参数检查
if (ciphertext.isEmpty() || key.isEmpty() || iv.isEmpty()) {
errMessage = "decryptCiphertext_AES: Invalid input parameters.";
return false;
}
// 密钥长度为 32 字节,IV 长度为 16 字节
QByteArray keyBytes = QByteArray::fromBase64(key.toUtf8());
QByteArray ivBytes = QByteArray::fromBase64(iv.toUtf8());
// 密钥和 IV 长度检查
if (keyBytes.size() != AES_KEY_SIZE_32 ||
ivBytes.size() != AES_BLOCK_SIZE_16) {
errMessage = "decryptCiphertext_AES: Invalid key or iv size.";
return false;
}
// 创建加密上下文
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
errMessage = "decryptCiphertext_AES: Failed to create cipher context.";
return false;
}
// 初始化加密上下文
if (EVP_DecryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(keyBytes.constData()),
reinterpret_cast<const unsigned char *>(ivBytes.constData())) != 1) {
EVP_CIPHER_CTX_free(ctx);
errMessage = "decryptCiphertext_AES: Failed to initialize cipher context.";
return false;
}
// 密文转换为字节数组
QByteArray cipherArray = QByteArray::fromHex(ciphertext.toUtf8());
if (cipherArray.isEmpty()) { // Hex 解码失败
EVP_CIPHER_CTX_free(ctx);
errMessage = "decryptCiphertext_AES: Failed to decode ciphertext.";
return false;
}
// 分配足够的缓冲区(密文长度 + 块大小)
const unsigned char *cipherTextPtr =
reinterpret_cast<const unsigned char *>(cipherArray.constData());
int cipherTextLen = cipherArray.size();
std::vector<unsigned char> plainText(cipherTextLen + AES_BLOCK_SIZE_16);
int len = 0, totalLen = 0;
// 解密
if (EVP_DecryptUpdate(ctx, plainText.data(), &len, cipherTextPtr,
cipherTextLen) != 1) {
EVP_CIPHER_CTX_free(ctx);
errMessage = "decryptCiphertext_AES: Failed to decrypt ciphertext.";
return false;
}
totalLen = len;
// 解密后的数据可能大于密文长度,需要填充
if (EVP_DecryptFinal_ex(ctx, plainText.data() + len, &len) != 1) {
EVP_CIPHER_CTX_free(ctx);
errMessage = "decryptCiphertext_AES: Failed to finalize decryption.";
return false;
}
totalLen += len;
// 调整到实际大小
plainText.resize(totalLen);
plaintext = QString::fromUtf8(
reinterpret_cast<const char *>(plainText.data()), totalLen);
// 释放加密上下文
EVP_CIPHER_CTX_free(ctx);
return true;
}
bool QtEncryptDecrypt::encryptFile_AES(const QString &inputFile,
const QString &outputFile,
const QString &keyStr,
const QString &ivStr,
QString &errMessage) {
// 清空输出参数
errMessage.clear();
// 参数有效性检查
if (inputFile.isEmpty() || outputFile.isEmpty() || keyStr.isEmpty() ||
ivStr.isEmpty()) {
errMessage = "encryptFile_AES: Invalid input parameters.";
return false;
}
// 转换密钥和IV
QByteArray keyBytes = keyStr.toUtf8();
QByteArray ivBytes = ivStr.toUtf8();
if (keyBytes.size() != AES_KEY_SIZE_32 ||
ivBytes.size() != AES_BLOCK_SIZE_16) {
errMessage = "encryptFile_AES: Invalid key or iv size.";
return false;
}
// 打开文件
QFile inFile(inputFile);
QFile outFile(outputFile);
if (!inFile.open(QIODevice::ReadOnly)) {
errMessage = "encryptFile_AES: Failed to open input file.";
return false;
}
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
errMessage = "encryptFile_AES: Failed to open output file.";
inFile.close();
return false;
}
// 初始化加密上下文
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
inFile.close();
outFile.close();
errMessage = "encryptFile_AES: Failed to create cipher context.";
return false;
}
// 设置加密参数
if (1 != EVP_EncryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(keyBytes.constData()),
reinterpret_cast<const unsigned char *>(ivBytes.constData()))) {
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
errMessage = "encryptFile_AES: Failed to initialize cipher context.";
return false;
}
// 缓冲区分配
unsigned char inBuf[FILE_BUFFER_SIZE]{};
unsigned char outBuf[FILE_BUFFER_SIZE + AES_BLOCK_SIZE_16]; // 预留填充空间
int bytesRead = 0;
int outLen = 0;
bool success = true;
// 分块加密
while ((bytesRead = inFile.read(reinterpret_cast<char *>(inBuf),
FILE_BUFFER_SIZE)) > 0) {
// 处理当前数据块
if (1 != EVP_EncryptUpdate(ctx, outBuf, &outLen, inBuf, bytesRead)) {
errMessage = "encryptFile_AES: Failed to encrypt data block.";
success = false;
break;
}
// 写入加密数据
if (outFile.write(reinterpret_cast<char *>(outBuf), outLen) == -1) {
errMessage = "encryptFile_AES: Failed to write encrypted data.";
success = false;
break;
}
}
// 处理最终块(填充)
if (success && 1 != EVP_EncryptFinal_ex(ctx, outBuf, &outLen)) {
errMessage = "encryptFile_AES: Failed to finalize encryption.";
success = false;
} else if (outLen > 0) {
if (outFile.write(reinterpret_cast<char *>(outBuf), outLen) == -1) {
errMessage = "encryptFile_AES: Failed to write final encrypted data.";
success = false;
}
}
// 清理资源
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
// 如果失败则删除不完整的输出文件
if (!success) {
errMessage = "encryptFile_AES: Failed to encrypt file.";
outFile.remove();
}
return success;
}
bool QtEncryptDecrypt::decryptFile_AES(const QString &inputFile,
const QString &outputFile,
const QString &keyStr,
const QString &ivStr,
QString &errMessage) {
// 清空输出参数
errMessage.clear();
// 参数有效性检查
if (inputFile.isEmpty() || outputFile.isEmpty() || keyStr.isEmpty() ||
ivStr.isEmpty()) {
errMessage = "decryptFile_AES: Invalid input parameters.";
return false;
}
// 转换密钥和IV
QByteArray keyBytes = keyStr.toUtf8();
QByteArray ivBytes = ivStr.toUtf8();
if (keyBytes.size() != AES_KEY_SIZE_32 ||
ivBytes.size() != AES_BLOCK_SIZE_16) {
errMessage = "decryptFile_AES: Invalid key or iv size.";
return false;
}
// 打开文件
QFile inFile(inputFile);
QFile outFile(outputFile);
if (!inFile.open(QIODevice::ReadOnly)) {
errMessage = "decryptFile_AES: Failed to open input file.";
return false;
}
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
errMessage = "decryptFile_AES: Failed to open output file.";
inFile.close();
return false;
}
// 初始化解密上下文
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
inFile.close();
outFile.close();
errMessage = "decryptFile_AES: Failed to create cipher context.";
return false;
}
// 设置解密参数
if (1 != EVP_DecryptInit_ex(
ctx, EVP_aes_256_cbc(), nullptr,
reinterpret_cast<const unsigned char *>(keyBytes.constData()),
reinterpret_cast<const unsigned char *>(ivBytes.constData()))) {
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
errMessage = "decryptFile_AES: Failed to initialize cipher context.";
return false;
}
// 缓冲区分配
unsigned char inBuf[FILE_BUFFER_SIZE]{};
unsigned char outBuf[FILE_BUFFER_SIZE + AES_BLOCK_SIZE_16]; // 预留填充空间
int bytesRead = 0;
int outLen = 0;
bool success = true;
// 分块解密
while ((bytesRead = inFile.read(reinterpret_cast<char *>(inBuf),
FILE_BUFFER_SIZE)) > 0) {
// 处理当前数据块
if (1 != EVP_DecryptUpdate(ctx, outBuf, &outLen, inBuf, bytesRead)) {
errMessage = "decryptFile_AES: Failed to decrypt data block.";
success = false;
break;
}
// 写入解密数据
if (outFile.write(reinterpret_cast<char *>(outBuf), outLen) == -1) {
errMessage = "decryptFile_AES: Failed to write decrypted data.";
success = false;
break;
}
}
// 处理最终块(去除填充)
int finalLen = 0;
if (success && 1 != EVP_DecryptFinal_ex(ctx, outBuf, &finalLen)) {
errMessage = "decryptFile_AES: Failed to finalize decryption.";
success = false;
} else if (finalLen > 0) {
if (outFile.write(reinterpret_cast<char *>(outBuf), finalLen) == -1) {
errMessage = "decryptFile_AES: Failed to write final decrypted data.";
success = false;
}
}
// 清理资源
EVP_CIPHER_CTX_free(ctx);
inFile.close();
outFile.close();
// 如果失败则删除不完整的输出文件
if (!success) {
errMessage = "decryptFile_AES: Failed to decrypt file.";
outFile.remove();
}
return success;
}
// qtencryptdecrypt.cpp
void QtEncryptDecrypt::encryptFileChunked_AES(const QString &inputPath,
const QString &outputBasePath,
const QByteArray &key,
const QByteArray &iv) {
m_encryptor = new ParallelEncryptor(this);
// 连接信号
connect(m_encryptor, &ParallelEncryptor::completed, [this](bool success) {
QStringList parts = m_encryptor->encryptedParts();
QString error = m_encryptor->lastError();
emit encryptionFinished(success, parts, error);
m_encryptor->deleteLater();
});
connect(m_encryptor, &ParallelEncryptor::errorOccurred,
[this](const QString &error) {
emit encryptionFinished(false, QStringList(), error);
m_encryptor->deleteLater();
});
connect(m_encryptor, &ParallelEncryptor::progressChanged, this,
[=](qint64 totoal, qint64 current) {
emit encryptionProgressChanged(totoal, current);
});
// 启动加密
m_encryptor->encryptFile(inputPath, outputBasePath, key, iv);
}
void QtEncryptDecrypt::decryptFileChunked_AES(
const QString &outputFileName, const QByteArray &key, const QByteArray &iv,
const QStringList &encryptedParts) {
m_decryptor = new ParallelDecryptor(this);
// 连接信号
connect(m_decryptor, &ParallelDecryptor::completed, [this](bool success) {
QString error = m_decryptor->lastError();
emit decryptionFinished(success, error);
m_decryptor->deleteLater();
});
connect(m_decryptor, &ParallelDecryptor::errorOccurred,
[this](const QString &error) {
emit decryptionFinished(false, error);
m_decryptor->deleteLater();
});
connect(m_decryptor, &ParallelDecryptor::progressChanged, this,
[=](qint64 totoal, qint64 current) {
emit decryptionProgressChanged(totoal, current);
});
// 启动解密
m_decryptor->decryptFile(encryptedParts, outputFileName, key, iv);
}
bool QtEncryptDecrypt::generateRSAKeyPair(QString &pubKeyStr,
QString &privKeyStr,
QString &errMessage) {
// 清理输出参数
pubKeyStr.clear();
privKeyStr.clear();
errMessage.clear();
EVP_PKEY_CTX *ctx = nullptr;
EVP_PKEY *pkey = nullptr;
BIO *bio_pub = nullptr;
BIO *bio_priv = nullptr;
bool success = false;
BUF_MEM *priv_mem = nullptr;
BUF_MEM *pub_mem = nullptr;
// 生成密钥对
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
if (!ctx || EVP_PKEY_keygen_init(ctx) <= 0 ||
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0 ||
EVP_PKEY_keygen(ctx, &pkey) <= 0) {
errMessage = "Failed to generate RSA key pair.";
goto cleanup;
}
// 导出公钥
bio_pub = BIO_new(BIO_s_mem());
if (PEM_write_bio_PUBKEY(bio_pub, pkey) != 1) {
errMessage = "Failed to write public key.";
goto cleanup;
}
BIO_get_mem_ptr(bio_pub, &pub_mem);
if (pub_mem && pub_mem->data && pub_mem->length > 0) {
pubKeyStr = QString::fromLatin1(pub_mem->data, pub_mem->length);
} else {
errMessage = "Public key data is empty.";
goto cleanup;
}
// 导出私钥
bio_priv = BIO_new(BIO_s_mem());
if (PEM_write_bio_PrivateKey(bio_priv, pkey, nullptr, nullptr, 0, nullptr,
nullptr) != 1) {
errMessage = "Failed to write private key.";
goto cleanup;
}
BIO_get_mem_ptr(bio_priv, &priv_mem);
if (priv_mem && priv_mem->data && priv_mem->length > 0) {
privKeyStr = QString::fromLatin1(priv_mem->data, priv_mem->length);
} else {
errMessage = "Private key data is empty.";
goto cleanup;
}
success = true;
cleanup:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
BIO_free_all(bio_pub); // 使用 BIO_free_all 确保彻底释放
BIO_free_all(bio_priv);
return success;
}
// 功能为RSA加密数据
bool QtEncryptDecrypt::encryptPlaintext_RSA(const QString &plaintext,
const QString &publicKey,
QString &ciphertext,
QString &errMessage) {
// 清理输出参数
ciphertext.clear();
errMessage.clear();
// 参数有效性检查
if (plaintext.isEmpty() || publicKey.isEmpty()) {
errMessage = "encryptPlaintext_RSA: Invalid input parameters.";
return false;
}
// 将QString转换为字节数组
const QByteArray plainData = plaintext.toUtf8();
const QByteArray pubKeyData = publicKey.toUtf8();
// 创建内存BIO加载公钥
BIO *bio = BIO_new_mem_buf(pubKeyData.constData(), pubKeyData.size());
if (!bio) {
errMessage =
"encryptPlaintext_RSA: Failed to allocate memory BIO for public key.";
return false;
}
// 从PEM格式加载公钥
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr);
BIO_free(bio);
if (!pkey) {
errMessage =
"encryptPlaintext_RSA: Failed to load public key from PEM format.";
return false;
}
// 检查公钥类型是否为RSA
if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) {
EVP_PKEY_free(pkey);
errMessage = "encryptPlaintext_RSA: Public key is not an RSA key.";
return false;
}
// 创建加密上下文
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, nullptr);
if (!ctx) {
EVP_PKEY_free(pkey);
errMessage = "encryptPlaintext_RSA: Failed to create EVP_PKEY context.";
return false;
}
// 初始化加密操作
int ret = EVP_PKEY_encrypt_init(ctx);
if (ret <= 0) {
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
errMessage = "encryptPlaintext_RSA: Failed to initialize encryption.";
return false;
}
// 设置使用OAEP填充模式(更安全的填充方式)
ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
if (ret <= 0) {
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
errMessage = "encryptPlaintext_RSA: Failed to set RSA padding.";
return false;
}
// 计算加密后的最大缓冲区大小
size_t cipherLen = 0;
ret = EVP_PKEY_encrypt(
ctx, nullptr, &cipherLen,
reinterpret_cast<const unsigned char *>(plainData.constData()),
plainData.size());
if (ret <= 0 || cipherLen == 0) {
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
errMessage = "encryptPlaintext_RSA: Failed to calculate cipher length.";
return false;
}
// 分配加密缓冲区
unsigned char *cipherBuf =
static_cast<unsigned char *>(OPENSSL_malloc(cipherLen));
if (!cipherBuf) {
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
errMessage =
"encryptPlaintext_RSA: Failed to allocate memory for cipher buffer.";
return false;
}
// 执行实际加密操作
ret = EVP_PKEY_encrypt(
ctx, cipherBuf, &cipherLen,
reinterpret_cast<const unsigned char *>(plainData.constData()),
plainData.size());
bool success = (ret > 0);
// 转换为Base64字符串
if (success) {
QByteArray cipherArray(reinterpret_cast<const char *>(cipherBuf),
cipherLen);
ciphertext = QString::fromLatin1(cipherArray.toBase64());
} else {
errMessage = "encryptPlaintext_RSA: Failed to encrypt data.";
}
// 清理资源
OPENSSL_free(cipherBuf);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return success;
}
// 功能为RSA解密数据
bool QtEncryptDecrypt::decryptCiphertext_RSA(const QString &ciphertext,
const QString &privateKey,
QString &plaintext,
QString &errMessage) {
// 清理输出参数
plaintext.clear();
errMessage.clear();
// 参数有效性检查
if (ciphertext.isEmpty() || privateKey.isEmpty()) {
errMessage = "decryptCiphertext_RSA: Invalid empty input";
return false;
}
// 将Base64密文转换为二进制
QByteArray cipherData = QByteArray::fromBase64(ciphertext.toLatin1());
if (cipherData.isEmpty()) {
errMessage = "decryptCiphertext_RSA: Base64 decoding failed";
return false;
}
// 创建内存BIO加载私钥
QByteArray privKeyData = privateKey.toUtf8(); // 转换为字节数组, 用于加载私钥
BIO *bio = BIO_new_mem_buf(privKeyData.constData(), privateKey.size());
if (!bio) {
errMessage = "decryptCiphertext_RSA: Memory BIO creation failed";
return false;
}
// 从PEM格式加载私钥(无密码)
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
BIO_free(bio);
if (!pkey) {
errMessage = "decryptCiphertext_RSA: Private key loading failed";
return false;
}
// 创建解密上下文
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, nullptr);
if (!ctx) {
errMessage = "decryptCiphertext_RSA: EVP_PKEY Context creation failed";
EVP_PKEY_free(pkey);
return false;
}
// 初始化解密操作
if (EVP_PKEY_decrypt_init(ctx) <= 0) {
errMessage = "decryptCiphertext_RSA: EVP_PKEY Decrypt init failed";
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return false;
}
// 设置OAEP填充模式(必须与加密时一致)
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
errMessage = "decryptCiphertext_RSA: Set padding failed";
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return false;
}
// 获取解密后数据长度
size_t plainLen = 0;
if (EVP_PKEY_decrypt(
ctx, nullptr, &plainLen,
reinterpret_cast<const unsigned char *>(cipherData.constData()),
cipherData.size()) <= 0) {
errMessage = "decryptCiphertext_RSA: Get length failed";
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return false;
}
// 分配明文缓冲区
unsigned char *plainBuf =
static_cast<unsigned char *>(OPENSSL_malloc(plainLen));
if (!plainBuf) {
errMessage = "decryptCiphertext_RSA: Memory allocation failed";
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return false;
}
// 执行实际解密
int ret = EVP_PKEY_decrypt(
ctx, plainBuf, &plainLen,
reinterpret_cast<const unsigned char *>(cipherData.constData()),
cipherData.size());
bool success = (ret > 0);
// 转换结果到QString
if (success) {
QByteArray plainArray(reinterpret_cast<const char *>(plainBuf), plainLen);
plaintext = QString::fromUtf8(plainArray);
} else {
errMessage = "decryptCiphertext_RSA: Decryption failed";
ERR_print_errors_fp(stderr); // 打印详细错误
}
// 清理资源
OPENSSL_clear_free(plainBuf, plainLen); // 安全擦除内存
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return success;
}
test.cpp
#include "test.h"
Test::Test(QObject *parent)
: QObject(parent)
{}
Test::~Test()
{}
textwidget.cpp
#include "textwidget.h"
TextWidget::TextWidget(QWidget* parent)
: QWidget(parent)
{
initTextWidget();
}
void TextWidget::initTextWidget()
{
plainTextEdit = new QTextEdit(this);
plainTextEdit->setMinimumSize(400, 300);
plainTextEdit->setPlaceholderText("Enter plain text here...");
plainTextGroupBox = new QGroupBox("Plain Text", this);
cipherTextEdit = new QTextEdit(this);
cipherTextEdit->setMinimumSize(400, 300);
cipherTextEdit->setPlaceholderText("Cipher text will be displayed here...");
cipherTextGroupBox = new QGroupBox("Cipher Text", this);
plainTextLayout = new QVBoxLayout(this);
plainTextLayout->addWidget(plainTextEdit);
plainTextGroupBox->setLayout(plainTextLayout);
cipherTextLayout = new QVBoxLayout(this);
cipherTextLayout->addWidget(cipherTextEdit);
cipherTextGroupBox->setLayout(cipherTextLayout);
mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(plainTextGroupBox);
mainLayout->addWidget(cipherTextGroupBox);
this->setLayout(mainLayout);
}
TextWidget::~TextWidget()
{
}