安全文件傳輸系統項目報告
項目概述
本實驗旨在設計并實現一個完整的安全文件管理系統,基于SM2+SM3+SM4混合密碼體系,構建了一個具備高安全性的C/S架構文件傳輸平臺。項目采用C/S架構,使用Qt框架開發,滿足Linux系統調用、Socket網絡編程、多線程處理等技術要求。
開發環境
- 處理器:x86_64架構處理器
- 操作系統:Ubuntu 20.04
- 開發框架:Qt5
- 數據庫:SQLite 3
- 密碼庫:gmssl
Gitee地址:
https://gitee.com/li-zhen1215/homework/tree/master/Secure%20File%20Transfer%20System
一、 功能完成以及完善情況
系統流程圖
用戶登錄
系統采用登錄驗證機制作為入口。用戶啟動客戶端后,首先進入登錄界面:
- 賬號驗證:
- 若用戶尚未注冊賬號,系統將引導其完成注冊流程,創建合法用戶信息;
- 若用戶已有賬號,則可直接輸入憑證完成身份驗證。
進入主界面
登錄成功后,用戶將進入系統主界面,該界面集成了全部核心功能模塊,。
文件管理功能
主界面提供了一系列文件傳輸和管理功能,具體包括:
- 文件上傳:用戶可將本地文件上傳至服務器;
- 文件下載:可從服務器下載所需文件到本地;
- 文件刪除:允許用戶刪除自己上傳的文件;
- 刷新列表:實時刷新當前文件列表,查看最新文件信息;
- 下載日志:支持用戶查看文件下載歷史記錄,實現基本的審計追蹤。
注銷與退出
用戶完成所需操作后,可選擇注銷賬號,安全退出系統,確保賬號信息和數據傳輸的安全性。
系統特點
- 支持多用戶并發訪問:通過多線程/多連接機制,系統可同時處理多個用戶請求;
- 審計功能完善:系統記錄用戶操作日志,有助于行為追蹤和系統安全審查。
1、總體架構完成情況
C/S架構實現
- 服務器端:
ServerCore
類繼承QTcpServer
,實現多線程并發處理 - 客戶端: Qt GUI應用程序,提供用戶友好的圖形界面
- 網絡通信: 基于TCP Socket的可靠數據傳輸
系統架構圖
2 、核心模塊架構
2.1 客戶端架構
Client/
├── MainWindow // 主界面管理
├── LoginWindow // 登錄界面
├── RegisterWindow // 注冊界面
├── FileTransfer // 文件傳輸核心
├── SecurityManager // 密碼學操作
└── AuditLogger // 審計日志
2.2 服務器架構
Server/
├── ServerCore // 服務器核心 (繼承QTcpServer)
├── ClientHandler // 客戶端連接處理
├── Database // 數據庫操作
├── SecurityManager // 服務器密碼學管理
└── AuditLogger // 服務器審計系統
3、功能完成以及完善情況
3.1 用戶管理系統
當用戶首次使用系統時,需要進行注冊。用戶名和口令是進入系統的憑證,用戶名用作實現訪問控制功能,而口令作為驗證用戶身份的唯一憑證,只有口令和用戶名相對應,用戶才能正確進入系統。
3.1.1 用戶注冊功能
實現思路:
- 用戶輸入用戶名和密碼
- 客戶端發送注冊請求到服務器
- 服務器進行SM3密碼哈希處理
- 存儲到SQLite數據庫
為確保身份鑒別的安全性,口令僅保存經過 SM3 哈希算法計算后的哈希值,并采用加鹽機制以增強抗攻擊能力。
核心實現代碼:
// 密碼哈希處理 - SecurityManager類
QByteArray SecurityManager::hashPasswordWithSalt(const QString& password, const QByteArray& salt) {QByteArray actualSalt = salt.isEmpty() ? generateSalt() : salt;QByteArray combined = password.toUtf8() + actualSalt;// 10000輪SM3哈希運算 (PBKDF2-SM3)QByteArray hash = combined;const int rounds = 10000;for (int i = 0; i < rounds; i++) {SM3_CTX ctx;sm3_init(&ctx);sm3_update(&ctx, (const uint8_t*)hash.constData(), hash.size());uint8_t dgst[32];sm3_finish(&ctx, dgst);hash = QByteArray((char*)dgst, 32);}return actualSalt + hash; // [鹽值32字節][哈希32字節]
}
注冊用戶界面
服務器端注冊日志輸出
3.1.2 用戶登錄認證
注冊成功后,用戶可以進入程序主界面,對自己的文件進行管理。
實現思路:
- 用戶輸入憑據后,客戶端與服務器進行SM2密鑰協商
- 建立安全信道后發送登錄請求
- 服務器驗證密碼哈希
- 建立用戶會話
核心實現代碼:
// SM2密鑰協商 - 客戶端
bool SecurityManager::performClientHandshake(QTcpSocket* socket) {// 1. 接收服務器SM2公鑰QByteArray serverPublicKeyBytes = readData(socket, 64);// 2. 生成會話密鑰sessionKey = generateRandomKey(16);// 3. SM2加密會話密鑰QByteArray encryptedSessionKey = encryptWithSM2PublicKey(sessionKey, serverPublicKeyBytes);// 4. 發送加密的會話密鑰socket->write(encryptedSessionKey);// 5. 等待握手確認QString response = readString(socket);return response == "HANDSHAKE_OK";
}
系統登錄界面
** SM2密鑰協商過程日志**
用戶注銷后,會返回登錄界面,此時用戶已從服務器中下線。
3.2 安全文件傳輸系統
這個模塊主要實現文件的安全傳輸,確保用戶數據的安全性。同時,在這里使用了大量的Linux系統調用,尤其是文件調用。
3.2.1 文件上傳功能
實現流程:
- 用戶選擇文件
- 客戶端使用SM4加密文件數據
- 計算文件SM3哈希值
- 分塊傳輸到服務器
- 服務器解密并驗證完整性
核心實現代碼:
// SM4文件加密 - FileTransfer類
bool FileTransfer::uploadFile(const QString& filepath) {QFile file(filepath);if (!file.open(QIODevice::ReadOnly)) return false;QByteArray fileData = file.readAll();// SM4加密QByteArray encryptedData = securityManager->encryptSM4(fileData);QJsonObject request;request["type"] = "upload";request["filename"] = QFileInfo(filepath).fileName();request["filesize"] = encryptedData.size();request["filehash"] = QString(securityManager->calculateSM3Hash(fileData).toHex());// 發送請求頭socket->write(QJsonDocument(request).toJson());const int chunkSize = 8192;int bytesWritten = 0;while (bytesWritten < encryptedData.size()) {QByteArray chunk = encryptedData.mid(bytesWritten, chunkSize);int written = socket->write(chunk);bytesWritten += written;emit uploadProgress(bytesWritten, encryptedData.size());}return true;
}
文件管理界面
文件上傳成功后,可以點擊四個表頭,以根據名稱、類型、大小或上傳時間對文件進行排序。點擊一次為升序排序,再次點擊則為降序排序。
服務器端文件接收日志
3.2.2 文件下載功能
實現要點:
- 用戶權限驗證(只能下載自己的文件)
- SM4解密文件數據
- 完整性校驗
選擇下載地址
服務器端發送文件日志
3.3 審計日志系統
3.3.1 日志記錄架構
設計思路:
- 單例模式設計,線程安全
- 多級別日志:DEBUG、INFO、WARNING、ERROR、CRITICAL
- 多分類日志:SYSTEM、AUTH、CRYPTO、FILE_OP、DATABASE、NETWORK、SECURITY
- 按用戶和日期分離存儲
核心實現代碼:
// 審計日志記錄 - AuditLogger類
class AuditLogger {
public:enum LogLevel { DEBUG, INFO, WARNING, ERROR, CRITICAL };enum LogCategory { SYSTEM, AUTH, CRYPTO, FILE_OP, DATABASE, NETWORK, SECURITY };static AuditLogger& getInstance() {static AuditLogger instance;return instance;}void log(LogLevel level, LogCategory category, const QString& username, const QString& action, const QString& resource, bool success, const QString& details = "") {QMutexLocker locker(&logMutex);QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");QString logEntry = QString("[%1] [%2] [%3] %4: %5 on '%6' - %7 (%8)").arg(timestamp).arg(levelToString(level)).arg(categoryToString(category)).arg(username).arg(action).arg(resource).arg(success ? "SUCCESS" : "FAILED").arg(details);// 寫入系統日志writeToSystemLog(logEntry);// 寫入用戶個人日志if (!username.isEmpty() && username != "SYSTEM") {writeToUserLog(username, logEntry);}}
};
3.3.2 用戶日志下載
實現功能:
- 客戶端可以下載自己的操作日志
- 支持日期范圍篩選
- SM4加密傳輸確保安全
** 日志下載界面**
** 用戶日志內容**
** 日志下載事件**
以下是你提供內容的潤色和擴展版,保持結構清晰、語言規范,并適度增加技術細節和邏輯說明,適合用于實驗報告:
4、其他功能
4.1 Socket編程
本系統采用基于 Qt 網絡模塊的 Socket 編程實現了客戶端與服務器之間的可靠通信。
服務器端:
服務器端通過繼承 QTcpServer 類,實現了基于 TCP 協議的監聽與連接管理功能。當檢測到新的客戶端連接請求時,系統會自動創建一個獨立的 ClientHandler 線程對象,專門負責處理該客戶端的所有通信任務。此種“主線程監聽 + 子線程處理”的結構設計,能夠有效支持多客戶端并發訪問,顯著提升了系統的并發處理能力與整體穩定性。
客戶端:
客戶端采用 QTcpSocket 實現與服務器的連接功能。通信模塊被封裝為 FileTransfer 類,統一管理網絡連接的建立、文件數據的分片發送與接收、錯誤處理與狀態監控等邏輯。該模塊的封裝提高了通信代碼的可復用性與可維護性,使得客戶端邏輯更加簡潔明晰,便于后期拓展和維護。
服務器端關鍵實現:
class ServerCore : public QTcpServer {Q_OBJECTpublic:void start(quint16 port) {if (this->listen(QHostAddress::Any, port)) {qDebug() << "服務器啟動,監聽端口:" << port;} else {qDebug() << "服務器啟動失敗:" << this->errorString();}}protected:// 重寫虛函數,處理新連接void incomingConnection(qintptr socketDescriptor) override {ClientHandler *handler = new ClientHandler(socketDescriptor, this);connect(handler, &QThread::finished, handler, &QObject::deleteLater);handler->start(); // 啟動新線程處理客戶端}
};
該設計模式通過將每個客戶端請求交由獨立線程處理,有效避免了主線程阻塞的問題,同時保障了系統在高并發情況下的穩定運行。
4.2 Linux系統調用支持
系統在文件操作模塊中大量使用了基于 Qt 封裝的 Linux 系統調用,確保文件傳輸的高效性與兼容性。文件的創建、寫入、讀取等底層操作均對應于實際的系統調用,如 open
、write
、read
、fsync
和 stat
等。
文件管理模塊關鍵實現:
class FileManager {
public:// 文件創建和寫入static bool saveFile(const QString& filepath, const QByteArray& data) {QFile file(filepath);QDir dir = QFileInfo(filepath).dir();if (!dir.exists()) {dir.mkpath("."); // 等效于 mkdir}if (!file.open(QIODevice::WriteOnly)) {qDebug() << "文件創建失敗:" << file.errorString();return false;}qint64 bytesWritten = file.write(data); // 等效于 writeif (bytesWritten != data.size()) {qDebug() << "文件寫入不完整";return false;}file.flush(); // 等效于 fsyncreturn true;}// 文件讀取static QByteArray loadFile(const QString& filepath) {QFile file(filepath);if (!file.exists()) { // 等效于 statqDebug() << "文件不存在:" << filepath;return QByteArray();}if (!file.open(QIODevice::ReadOnly)) {qDebug() << "文件打開失敗:" << file.errorString();return QByteArray();}return file.readAll(); // 等效于 read}
};
4.3 身份鑒別及訪問控制
系統在身份認證和訪問控制方面引入了基于角色的權限管理機制。用戶在登錄時必須經過身份鑒別,認證成功后,系統會根據其賬號信息為其分配對應的權限范圍。普通用戶僅能訪問自己上傳的文件,無法訪問其他用戶的數據,從而有效保障了數據的隔離性和安全性。
此外,為增強身份認證的安全性,系統采用口令加密存儲機制,使用 SM3 哈希算法對用戶口令進行摘要處理,并加入隨機鹽值(salt)進行混淆,以防止彩虹表攻擊和哈希碰撞帶來的威脅。認證流程在前后端之間通過安全通道進行,確保用戶憑據在傳輸過程中不會被竊取或篡改。
這種精細化的訪問控制策略不僅提升了系統的安全等級,也符合多用戶環境下的文件管理需求。
二、安全性與密碼完成以及完善過程
1、安全性設計與密碼完成
1.1 SM3密碼哈希存儲機制
本系統在用戶身份認證中采用SM3哈希與加鹽機制提升安全性。用戶注冊時,系統生成32位隨機鹽值并與口令組合,使用SM3進行初始化哈希后執行1000輪迭代加密,最終將鹽值與哈希結果組合存入數據庫。登錄時,系統提取存儲的鹽值和哈希,使用用戶輸入的口令重新執行相同的加密流程,最后將計算結果與數據庫中的哈希值進行比對,以驗證身份是否匹配,確保口令安全存儲與驗證的完整性。
SM3加密算法實現
QByteArray hashPasswordWithSalt(const QString& password, const QByteArray& salt = QByteArray()) {QByteArray actualSalt = salt.isEmpty() ? generateSalt() : salt;QByteArray combined = password.toUtf8() + actualSalt;// 多輪哈希 (PBKDF2 密鑰拉伸)QByteArray hash = combined;const int rounds = 10000; // 10000輪SM3哈希SM3_CTX ctx;uint8_t dgst[32];for (int i = 0; i < rounds; i++) {sm3_init(&ctx);sm3_update(&ctx, (const uint8_t*)hash.constData(), hash.size());sm3_finish(&ctx, dgst);hash = QByteArray((char*)dgst, 32);}// 返回 [32字節鹽值] + [32字節哈希值]return actualSalt + hash;
}
1.2 混合密碼系統實現
混合密碼系統的實現流程從客戶端啟動開始。客戶端首先生成一對SM2密鑰(公鑰和私鑰),用于后續的密鑰交換與加密通信。服務器端在啟動時加載預先配置好的SM2密鑰對,準備與客戶端進行密鑰協商。在連接建立后,服務器向客戶端發送其SM2公鑰,客戶端接收后,結合自身私鑰生成對稱加密用的SM4會話密鑰,并使用服務器公鑰對該密鑰加密后發送回服務器。
服務器接收到加密后的會話密鑰后,使用自身的SM2私鑰進行解密,從而獲取SM4密鑰,雙方完成共享。為確保通信安全,系統在握手階段進行確認,確保SM4密鑰協商成功并一致,建立安全通信通道。每次通信會話系統都會生成獨立的SM4密鑰,并定期更新,降低長期使用帶來的安全風險。
在數據傳輸過程中,客戶端與服務器使用協商的SM4密鑰進行加解密操作,確保數據傳輸的機密性與完整性。該混合密碼機制結合SM2的密鑰交換優勢與SM4的高效對稱加密能力,有效保障了通信過程中的數據安全。
1.2.1 SM2橢圓曲線密鑰協商
- 客戶端密鑰生成
void SecurityManager::generateSM2KeyPair() {if (sm2_key_generate(&clientSM2Key) != 1) {qDebug() << "SM2密鑰對生成失敗!";return;}// 提取64字節公鑰 (x,y坐標各32字節)uint8_t public_key[64];if (sm2_z256_point_to_bytes(&clientSM2Key.public_key, public_key) == 1) {clientPublicKey = QByteArray((char*)public_key, 64);}
}
- 服務器端密鑰協商流程
bool performCryptoHandshake(QTcpSocket& socket) {// 1. 發送服務器SM2公鑰if (!sendServerPublicKey(socket)) return false;// 2. 接收客戶端加密的SM4會話密鑰if (!receiveEncryptedSessionKey(socket)) return false;// 3. 發送握手確認handshakeCompleted = true;return true;
}
1.2.2 SM4對稱加密系統
- 會話密鑰生成
void generateSessionKey() {// 生成128位(16字節)隨機會話密鑰sessionKey.resize(16);auto generator = QRandomGenerator::global();for (int i = 0; i < 16; i++) {sessionKey[i] = generator->bounded(256);}
}
- 會話密鑰生成
1.2.3 SM3完整性校驗
- 文件哈希計算
QString calculateHash(const QByteArray& data) {SM3_CTX ctx;uint8_t dgst[32];sm3_init(&ctx);sm3_update(&ctx, (const uint8_t*)data.constData(), data.size());sm3_finish(&ctx, dgst);return QByteArray((char*)dgst, 32).toHex();
}
1.3 SM4-CTR加密和SM3傳輸文件
本系統采用國密算法實現了文件在傳輸與存儲過程中的雙重安全保障。客戶端首先利用 SM4 加密算法的計數器模式(CTR) 對文件內容進行加密。該模式具有良好的并行性和隨機性,確保即使相同的明文也能生成不同的密文,從而有效防止內容泄露與模式分析。同時,客戶端對原始文件數據計算其 SM3 摘要值,作為數據完整性的校驗依據。
加密后的數據、生成的哈希值以及相關文件信息一并發送至服務器。服務器端接收到數據后,先用相同的會話密鑰和初始化向量(IV)進行 SM4-CTR 解密,還原出原始數據內容。隨后服務器重新計算一次該數據的 SM3 哈希值,并與客戶端發送的哈希值進行比對。若兩者一致,說明文件內容在傳輸過程中未被篡改,服務器則允許存入數據庫;若不一致,則拒絕保存并報告完整性校驗失敗。
該機制實現了文件加密傳輸與可信存儲的全流程防護,不僅保障了用戶數據的機密性,也有效防止了數據被非法篡改或偽造的風險,特別適用于對數據安全要求較高的業務場景。
2、完善過程
問題1:SM2公鑰生成全為零
問題現象
服務器生成的公鑰全為零,即:
服務器公鑰: 0000000000000000...(64字節全為0)
原因分析
錯誤的公鑰提取方式,直接使用內存拷貝結構體,導致公鑰數據不正確。
解決方案
修復前(錯誤)的代碼如下:
memcpy(publicKey, &serverSM2Key.public_key, 64);
修復后(正確)的代碼如下:
uint8_t public_key[64];
if (sm2_z256_point_to_bytes(&serverSM2Key.public_key, public_key) == 1) {serverPublicKey = QByteArray((char*)public_key, 64);
}
通過使用sm2_z256_point_to_bytes
函數正確提取公鑰數據,避免直接內存拷貝結構體的問題。
驗證結果
修復后,服務器公鑰正確生成,示例如下:
服務器公鑰: "14a527b1d209d437854e67007648abbaddc00118df6c52191185a2ed0ccb85fd..."
64字節公鑰正確生成
問題2 SM3密碼雜湊算法
問題現象
常規的加密安全程度不夠
解決方案
// 安全的密碼存儲方案
1. 生成32字節隨機鹽值
2. 密碼+鹽值組合
3. 進行10000輪SM3哈希運算
4. 存儲格式:[鹽值32字節][哈希32字節]
驗證結果
輸入測試密碼: "707"
鹽值長度: 32 內容: "0960b09cd073e238d6004605a217a8f6..."
開始 10000 輪哈希計算
最終結果長度: 64 內容: "0960b09cd073e238...9e8244c4dcd158494..."
10000輪哈希計算成功
問題3:SM2公鑰生成全為零
問題現象:
客戶端在注冊過程中出現無限等待服務器響應的情況。
原因分析:
由于服務器錯誤地將注冊請求當作登錄請求處理,導致注冊流程也嘗試執行密鑰協商。而注冊過程中并不需要密鑰協商,結果造成客戶端在等待服務器發送SM2公鑰的過程中陷入阻塞。
解決方案實現:
// 在服務器端增加請求類型檢測
void ServerCore::handleClientConnection(QTcpSocket* socket) {QString requestStr = readString(socket);QJsonObject obj = QJsonDocument::fromJson(requestStr.toUtf8()).object();QString requestType = obj["type"].toString();bool needsHandshake = true;if (requestType == "register") {needsHandshake = false; // 注冊跳過密鑰協商handleRegister(socket, obj);return;}if (needsHandshake) {if (!performServerHandshake(socket)) {socket->close();return;}}if (requestType == "login") {handleLogin(socket, obj);}
}
通過在服務器端添加對請求類型的判斷,明確區分注冊與登錄請求,僅在登錄請求中執行密鑰協商,避免了不必要的SM2操作。
驗證結果:
檢測到請求類型: "register"
檢測到注冊請求,跳過密鑰協商,直接處理注冊
注冊流程正常
登錄密鑰協商正常
問題4:多線程數據庫連接沖突
問題現象:
在多客戶端并發訪問的場景下,服務器端的數據庫操作偶爾失敗,表現為無法打開數據庫或數據讀寫異常。
原因分析:
Qt 中的 QSqlDatabase
對象在多線程環境下不具備線程安全性,若多個線程共用一個數據庫連接,會導致連接沖突或資源競爭,從而導致數據庫操作失敗。
解決方案實現:
// 為每個線程創建獨立的數據庫連接
QString dbName = "server_thread_" + QString::number((quintptr)QThread::currentThreadId());
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", dbName);
db.setDatabaseName("server.db");if (!db.open()) {qDebug() << "線程" << QThread::currentThreadId() << "數據庫連接失敗";return false;
}
通過為每個線程指定唯一的連接名,避免不同線程共享同一數據庫連接,有效解決并發沖突問題。
驗證結果:
線程ID: 0x16c 打開數據庫成功
線程ID: 0x1a0 打開數據庫成功
多線程并發訪問數據庫正常,未再出現連接失敗或寫入異常
三、項目改動和未來打算
在完成基礎系統功能開發后,我認真評估了現有成果的優缺點,并結合實際開發體驗與系統運行情況,未來可能從以下方面對系統進行完善:
1. 文件管理功能完善
- 文件重命名:支持用戶修改文件名,避免重名沖突并更新數據庫索引。
- 文件夾與目錄結構支持:引入“文件夾”概念,實現基本層級目錄管理,使用戶在面對大量文件時能更好地分類和管理。
2. 搜索與篩選功能
- 模糊搜索:支持文件名模糊匹配查詢;
- 組合查詢:可支持同時輸入多個關鍵詞、按多個維度聯合篩選。
3. 批量操作與交互優化
- 多文件批量上傳與下載:通過文件選擇器支持多選,并在傳輸隊列中統一管理;
- 批量刪除與分享:支持選中多個文件同時進行刪除、生成分享鏈接等操作;
- 文件上傳/下載進度條優化:提供總進度、剩余時間等信息提示,改善用戶等待體驗。
4. 文件加密與驗證機制強化
- 當前系統采用SM4加密和SM3哈希作為基礎安全手段;
- 后續可嘗試引入“數字簽名 + 時間戳”機制,防止篡改與偽造;
- 若部署于多用戶系統,可考慮對每個用戶使用獨立密鑰進行文件加密。