分段传输加密文件:非首段开头数据损坏问题求助
大文件AES加密分段传输后后续数据块开头损坏问题
C客户端加密文件后发送至Python服务器解密保存,小文件(单次读取1024字节)传输正常,但大文件分段传输时,除第一个数据块外,后续每个数据块开头部分损坏。经排查确认,损坏数据在C端加密第一个循环时产生。
C++端加密及发送代码
//Encrypt the data and save it to temporary file std::ofstream tempFile("EncryptedFile", std::ios::binary); char buffer[MAX_LEN]; std::cout << "The data inside buffer is:\n"; while (!transferFile.eof()) { std::fill_n(buffer, sizeof(buffer), '\0'); transferFile.read(buffer, sizeof(buffer)-1); std::streamsize bytesRead = transferFile.gcount(); std::cout << buffer; if (bytesRead > 0) { string encryptedChunk = aesWrapper.encrypt(buffer, bytesRead); tempFile.write(encryptedChunk.c_str(), encryptedChunk.size()); } } transferFile.close(); tempFile.close(); //Step 4: get the file size and send it std::ifstream tempFileRead("EncryptedFile", std::ios::binary | std::ios::ate); std::streamsize fileSize = tempFileRead.tellg(); tempFileRead.seekg(0, std::ios::beg); string header = createHeader(std::to_string(SEND_FILE)); header += ("\nPayload size: " + std::to_string(fileSize + fileName.length()) + "\nContent Size: ") + std::to_string(fileSize) + "\nFile Name: " + fileName; std::string utf8_request(header); boost::asio::write(s, boost::asio::buffer(utf8_request.c_str(), utf8_request.length())); while (tempFileRead) { tempFileRead.read(buffer, sizeof(buffer)-1); std::streamsize bytesRead = tempFileRead.gcount(); if (bytesRead > 0) { boost::asio::write(s, boost::asio::buffer(buffer, bytesRead)); } } tempFileRead.close(); std::remove("EncryptedFile");
Python端接收解密代码
iv = b"\x00" * 16 # just for practical use should not be set to 0 UUID = getUUID(request) AES_Key = DB.getAESKey(UUID) fileName = getFileName(request) ContentSize = int(getContentSize(request)) cipher = AES.new(AES_Key, AES.MODE_CBC, iv) decrypted_bytes = b'' while ContentSize > 0: data = server.getBinaryData() ContentSize -= len(data) decrypted_bytes += cipher.decrypt(data) decrypted_text = unpad(decrypted_bytes, AES.block_size) with open(fileName, 'wb') as file: file.write(decrypted_text)
问题根源及修复方案
核心问题
AES-CBC模式是链式加密,第一个块用初始IV加密,后续每个块的IV必须是前一个块的密文。原C++代码中,aesWrapper.encrypt若每次调用都重新初始化加密上下文(重置IV),会导致后续所有块用错误IV加密,最终解密时后续块开头出现损坏。
此外,文件读取循环条件while (!transferFile.eof())存在逻辑缺陷,会导致最后一次读取失败后仍执行加密操作,可能引入无效数据。
修复步骤
维护AES加密上下文状态
初始化一次加密器,分块加密时持续更新IV,而非每次加密都重新初始化:// 初始化加密器(仅执行一次) aesWrapper.initEncrypt(); std::ofstream tempFile("EncryptedFile", std::ios::binary); char buffer[MAX_LEN]; // 读取文件并分块加密 while (transferFile.read(buffer, sizeof(buffer))) { string encryptedChunk = aesWrapper.updateEncrypt(buffer, sizeof(buffer)); tempFile.write(encryptedChunk.c_str(), encryptedChunk.size()); } // 处理剩余数据及最终填充 std::streamsize bytesRead = transferFile.gcount(); if (bytesRead > 0) { string encryptedChunk = aesWrapper.updateEncrypt(buffer, bytesRead); tempFile.write(encryptedChunk.c_str(), encryptedChunk.size()); } string finalChunk = aesWrapper.finalEncrypt(); if (!finalChunk.empty()) { tempFile.write(finalChunk.c_str(), finalChunk.size()); } transferFile.close(); tempFile.close();修正文件读取循环逻辑
替换原eof()判断,改为先读取再判断实际读取字节数,避免无效循环:// 替换发送加密文件的循环 while (tempFileRead.read(buffer, sizeof(buffer))) { boost::asio::write(s, boost::asio::buffer(buffer, sizeof(buffer))); } std::streamsize bytesRead = tempFileRead.gcount(); if (bytesRead > 0) { boost::asio::write(s, boost::asio::buffer(buffer, bytesRead)); }优化二进制数据读取
加密后的文件是二进制格式,无需预留sizeof(buffer)-1的空间,直接读取整个缓冲区即可。
内容的提问来源于stack exchange,提问作者Dani Dubinskey
相关产品推荐
相关产品推荐

