使用Windows API开发的AES-256解密文件为何出现冗余文本?
文件解密后末尾出现冗余文本的问题分析与修复
核心问题
加密环节的错误
- 未标记最后一块数据:调用
CryptEncrypt时始终把final参数设为FALSE,导致所有数据块都被当作非最后一块处理,AES标准的PKCS#7填充不会自动添加。你手动把缓冲区扩展到块大小,但这不是规范的填充方式,解密时根本识别不出哪些是填充内容。 - 手动计算缓冲区大小多余:
CryptEncrypt本身会自动计算加密后的数据长度,手动算encryptedSize的操作完全没必要,还容易出错。
解密环节的错误
- 没处理填充去除:
CryptDecrypt的final参数也一直是FALSE,API不会自动去除PKCS#7填充,导致解密后的最后一块保留了加密时的填充字节,这就是你看到的末尾冗余文本。 - 缓冲区处理逻辑有问题:直接把输入缓冲区复制到输出缓冲区,没考虑解密后数据长度的变化,配合未标记最后一块的问题,填充就彻底没法被去除了。
修复后的关键代码
加密函数修改
bool encryptFile(char* sourcePath, char* destPath, char* password) { // 省略文件打开、密钥生成等原有代码... BYTE buffer[BUFFER_SIZE]; DWORD bytesRead, encryptedSize; BOOL success = TRUE; BOOL isFinal = FALSE; while ((bytesRead = fread(buffer, 1, BUFFER_SIZE, hSourceFile)) > 0) { // 判断是否为最后一块数据 isFinal = (bytesRead < BUFFER_SIZE); // 先调用CryptEncrypt获取加密所需的缓冲区大小 encryptedSize = bytesRead; if (!CryptEncrypt(hKey, NULL, isFinal, 0, NULL, &encryptedSize, 0)) { handleError(GetLastError()); success = FALSE; break; } BYTE* encryptedBuffer = (BYTE*)malloc(encryptedSize); if (!encryptedBuffer) { success = FALSE; break; } memcpy(encryptedBuffer, buffer, bytesRead); // 执行加密操作 if (!CryptEncrypt(hKey, NULL, isFinal, 0, encryptedBuffer, &bytesRead, encryptedSize)) { free(encryptedBuffer); handleError(GetLastError()); success = FALSE; break; } fwrite(encryptedBuffer, 1, bytesRead, hDestFile); free(encryptedBuffer); } // 省略资源释放等原有代码... }
解密函数修改
bool decryptFile(char* sourcePath, char* destPath, char* password) { // 省略文件打开、密钥生成等原有代码... BYTE bufferIn[BUFFER_SIZE]; BYTE bufferOut[BUFFER_SIZE + AES_BLOCK_SIZE]; // 预留空间处理填充 DWORD bytesRead, decryptedSize; BOOL success = TRUE; BOOL isFinal = FALSE; while ((bytesRead = fread(bufferIn, 1, BUFFER_SIZE, hSourceFile)) > 0) { // 读取后判断是否到达文件末尾 isFinal = feof(hSourceFile); memcpy(bufferOut, bufferIn, bytesRead); decryptedSize = bytesRead; if (!CryptDecrypt(hKey, NULL, isFinal, 0, bufferOut, &decryptedSize)) { handleError(GetLastError()); success = FALSE; break; } fwrite(bufferOut, 1, decryptedSize, hDestFile); } // 省略资源释放等原有代码... }
额外注意事项
- 判断最后一块时,必须在
fread之后调用feof,因为fread返回0才会触发EOF标记。 - 解密时输出缓冲区要预留比输入大的空间(比如加AES_BLOCK_SIZE),防止解密时缓冲区不足导致失败。
- 当前密钥派生没有加盐,相同密码会生成相同密钥,建议添加随机盐值写入加密文件开头,提高安全性。
内容的提问来源于stack exchange,提问作者Luzia Mas
相关产品推荐
相关产品推荐

