c - 加密系统文件时程序崩溃
问题描述
我编写了这段代码来加密和解密文件夹的内容,这两个功能在加密普通文件时都能正常工作,但是当我将文件夹更改为系统文件夹时,程序崩溃,当我在崩溃前检查最新文件时,我无法打开一些它们(文件在另一个程序中打开),其中一些我无法进行更改。我正在处理我认为的所有错误,但是当它到达另一个程序打开的文件时它仍然会崩溃,如何解决这个问题以忽略这些类型的文件并继续而不是崩溃?我认为发布的结构并不重要。
char ListFiles(const wchar_t* folder, CIPHER* conf)
{
wchar_t wildcard[MAX_PATH + 1];
swprintf(wildcard, sizeof(wildcard) / sizeof(*wildcard), L"%s\\*", folder);
WIN32_FIND_DATAW fd;
HANDLE handle = FindFirstFileW(wildcard, &fd);
if (handle == INVALID_HANDLE_VALUE) return 1;
do
{
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)
continue;
wchar_t path[MAX_PATH + 1];
swprintf(path, sizeof(path) / sizeof(*path), L"%s\\%s", folder, fd.cFileName);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
ListFiles(path, &conf);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
{
wprintf(L"%s\n", path);
FILE* f_dec;
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 1; // encryption
if (AES_L(conf, f_input, f_enc) != 0)
continue;
f_enc = _wfopen(path, L"rb");
f_dec = _wfopen(wcscat(path, L".decrypted"), L"wb");
if (!f_dec || !f_enc) {
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 0; // decryption
if (AES_L(conf, f_enc, f_dec) != 0)
continue;
puts("\n\n");
}
} while (FindNextFileW(handle, &fd));
FindClose(handle);
return 0;
}
char AES_L(CIPHER* params, FILE* ifp, FILE* ofp)
{
unsigned int inlen, outlen;
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
if (!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, params->key, params->iv, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
inlen = fread(inbuf, sizeof(*inbuf), params->bufsize, ifp);
if (ferror(ifp)) {
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (inlen < params->bufsize) /* Reached End of file */
break;
}
/* Now cipher the final block and write it out to file */
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 0;
}
更新:
void cleanup(FILE* ifp, FILE* ofp, unsigned char* inputBuf, unsigned char* outputBuf)
{
free(inputBuf);
free(outputBuf);
fclose(ifp);
fclose(ofp);
}
typedef struct {
unsigned int key_size;
unsigned int block_size;
unsigned int bufsize;
unsigned char* key;
unsigned char* iv;
unsigned int encrypt;
const EVP_CIPHER* cipher_type;
} CIPHER;
解决方案
我看到您的代码存在一些问题,尽管很难知道如果没有其余代码(例如,我们看不到该cleanup
方法)或您如何创建和初始化它们是否会导致崩溃params
。
第一个问题是您可能正在泄漏文件句柄。当您打开其中的文件时,ListFiles
您会成对打开它们,然后检查其中是否有NULL
,如果有,则继续循环。
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
如果f_input
正确打开但f_enc
失败怎么办?源文件将保持打开状态,直到程序结束。您应该分别检查它们中的每一个。
当您在以下位置分配内存时会出现类似的问题AES_L
:
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
return 1;
}
如果其中一个缓冲区(可能inbuf
是outbuf
崩溃,因为这会发生在内存已经非常低的情况下)。
当您为加密和解密文件创建路径时,可能会出现另一个问题。缓冲区的path
大小MAX_PATH+1
对于原始文件名来说已经足够了,但是随后您执行了一些wcscat
操作,这些操作会导致将额外的数据添加到路径中。如果原来的文件名已经快到MAX_PATH
极限了怎么办?当您执行时,wcscat
您将溢出堆栈中的缓冲区,这也可能导致崩溃。
最后,ListFiles
是递归的,所以如果有很多嵌套调用,你可能会用完堆栈,这也会导致崩溃(事实上,从我提到的问题来看,我认为这是主要的嫌疑人)。我会让它迭代。
无论如何,很难知道崩溃是否是由于这些问题造成的,最好的选择是在调试器中运行它。崩溃的错误消息会告诉你很多信息来确定原因。
推荐阅读
- jquery - 遍历 API 响应并显示
- python - 为什么不在 Python 中使用双精度?
- google-analytics - 如何知道 Google Analytics Property 是否会超过 10M Hit Limit?除了检查谷歌分析?谷歌提供的任何API?
- c - 不传递参数比较函数如何工作
- android - 缺少api密钥android Cloudinary上传错误
- reactjs - RadioGroup 未更新为选定的单选按钮
- c# - 如何有效地处理多个按钮和其他元素的可见性和 isEnabled
- algorithm - 有人可以直观地解释一下这段代码吗?
- matlab - 是否有一个 Matlab 函数可以将 rho 和 theta 重新投影到投影的纬度?
- react-native - 与 RN 0.60 自动链接不兼容