C++ 文件未完全解密,AES CBC模式。第一个块未被还原。WCAPI

C++ 文件未完全解密,AES CBC模式。第一个块未被还原。WCAPI,c++,windows,encryption,initialization-vector,wincrypt,C++,Windows,Encryption,Initialization Vector,Wincrypt,好的,我有5个文件正在加密。我没有设置静脉注射 第一个文件解密很好 然后剩余文件的第一个块不会被解密 因此,文件的解密率为99% 我试着将IV设置为静态值和随机值,结果相同 我加密的第一个文件不必是我解密的第一个文件,它就可以100%解密 这让我相信这和解密有关 所以对于加密,我导入一个aes密钥来创建一个密钥句柄 然后我加密一个文件并使用相同的密钥句柄移动到另一个文件 我是否应该为每个文件都设置一个新的密钥句柄 是否有清除钥匙手柄的功能 有人告诉我WCAPI正在使用上一个文件的最后一个块

好的,我有5个文件正在加密。我没有设置静脉注射

第一个文件解密很好

然后剩余文件的第一个块不会被解密

因此,文件的解密率为99%


我试着将IV设置为静态值和随机值,结果相同

我加密的第一个文件不必是我解密的第一个文件,它就可以100%解密

这让我相信这和解密有关


所以对于加密,我导入一个aes密钥来创建一个密钥句柄

然后我加密一个文件并使用相同的密钥句柄移动到另一个文件

我是否应该为每个文件都设置一个新的密钥句柄

是否有清除钥匙手柄的功能


有人告诉我WCAPI正在使用上一个文件的最后一个块作为下一个文件的IV

如果我可能误解了什么,请原谅

以下是解密_文件函数:

DWORD dwMode = CRYPT_MODE_CBC;

LPVOID aes_key = NULL;
LPVOID tmp_blk_buff = NULL;
DWORD bytes_read = NULL;

BOOL eof = FALSE;

DWORD tmp_blk_buff_size = TMP_BLOCK_BUFFER_SIZE(context->in_size);

tmp_blk_buff = VirtualAlloc(0, tmp_blk_buff_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

Utils::zero_mem(tmp_blk_buff, tmp_blk_buff_size);

LPVOID iv_ = NULL;
iv_ = VirtualAlloc(0, AES_BLOCK_SIZE_, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Utils::zero_mem(iv_, AES_BLOCK_SIZE_);

/*BYTE iv[AES_BLOCK_SIZE_] = {
    0xAD, 0xAD, 0xAD, 0xAD,
    0xAD, 0xAD, 0xAD, 0xAD,
    0xAD, 0xAD, 0xAD, 0xAD,
    0xAD, 0xAD, 0xAD, 0xAD
};
*/
//  Utils::copy_mem(iv_, AES_BLOCK_SIZE_, iv, AES_BLOCK_SIZE_);


//CryptSetKeyParam(context->aes_hKey, KP_IV, (BYTE*)&iv_, 0);

CryptSetKeyParam(context->aes_hKey, KP_MODE, (BYTE*)&dwMode, 0);

// Encrypt data
do{
    Utils::zero_mem(tmp_blk_buff, tmp_blk_buff_size);
    bytes_read = NULL;

    ReadFile(hFile_in, tmp_blk_buff, AES_BLOCK_SIZE_, &bytes_read, NULL);

    if (bytes_read < AES_BLOCK_SIZE_)
    {
        eof = TRUE;
    }

    if (!CryptDecrypt(context->aes_hKey, NULL, eof, 0,(LPBYTE)tmp_blk_buff, &bytes_read))
    {
        context->last_error = GetLastError();

        eof = TRUE;
    }

    WriteFile(hFile_out, tmp_blk_buff, bytes_read, &bytes_read, NULL);

} while (!eof);

// ===============
//  Zero and Free Allocated memory.
Utils::zero_mem(tmp_blk_buff, tmp_blk_buff_size);
VirtualFree(tmp_blk_buff, tmp_blk_buff_size, MEM_RELEASE);

return (DWORD)1;
DWORD dwMode=CRYPT\u MODE\u CBC;
LPVOID aes_key=NULL;
LPVOID tmp_blk_buff=NULL;
DWORD字节_read=NULL;
BOOL-eof=FALSE;
DWORD tmp_blk_buff_size=tmp_blk_buff_size=tmp_BLOCK_BUFFER_size(上下文->in_size);
tmp_blk_buff=VirtualAlloc(0,tmp_blk_buff_大小,MEM_COMMIT,MEM_RESERVE,PAGE_READWRITE);
Utils::零内存(tmp_blk_buff,tmp_blk_buff_大小);
LPVOID iv_u2;=空;
iv=虚拟化(0,AES_块_大小_,MEM_提交| MEM_保留,页_读写);
Utils::零内存(iv、AES、块大小);
/*字节iv[AES_块大小]={
0xAD,0xAD,0xAD,0xAD,
0xAD,0xAD,0xAD,0xAD,
0xAD,0xAD,0xAD,0xAD,
0xAD,0xAD,0xAD,0xAD
};
*/
//Utils::复制内存(iv、AES、块大小、iv、AES、块大小);
//CryptSetKeyParam(上下文->aes_hKey,KP_IV,(字节*)和IV_,0);
CryptSetKeyParam(上下文->aes_hKey,KP_模式,(字节*)和dwMode,0);
//加密数据
做{
Utils::零内存(tmp_blk_buff,tmp_blk_buff_大小);
字节_read=NULL;
读取文件(hFile\U in、tmp\U blk\U buff、AES\U BLOCK\U SIZE\U和字节\U read,NULL);
if(字节读取aes\u hKey,NULL,eof,0,(LPBYTE)tmp\u blk\u buff,&bytes\u read))
{
context->last_error=GetLastError();
eof=真;
}
写文件(hFile\U out、tmp\U blk\U buff、字节\U read和字节\U read、NULL);
}而(!eof);
// ===============
//零和空闲分配内存。
Utils::零内存(tmp_blk_buff,tmp_blk_buff_大小);
VirtualFree(tmp_blk_buff、tmp_blk_buff_大小、内存发布);
返回(DWORD)1;

是的,这表明您在给定的加密/解密对上使用了不同的IV

只有第一个块“损坏”的原因是CBC块错误只会传播到下一个块(而不是更远)

您要么是从上一个操作链接(如果跨文件重用上下文),要么不是将加密和解密的上下文初始化为相同的值

查看您的代码,您已经注释掉了
CryptSetKeyParam(..,KP_IV…)
,这意味着您的AES上下文可能在IV中有未知数据

一种比较常见的做法是,IV总是使用0,但在数据的开头放一块随机的“salt”。然后在解密时忽略第一个数据块。它只是用来随机化数据的

或者,你可以随机化IV,但将它以明文形式发送到加密邮件中。这也很常见

或者你可以在加密时随机输入IV,在真正的消息之前输入一块随机数据。在解密时使用任何IV并扔掉第一个块(因为它将是垃圾)


结果几乎相同(最终传输16个字节作为开销),但您应该在消息中加入一些随机性(通过IV或第一个块),以阻止短程攻击。

我使用CryptDuplicateKey并适当调用DestroyKey,解决了我的问题


使用复制键设置参数,保持原始键不被触碰。

我认为您将一个文件的最后一个块向前移动到下一个文件的第一个块是正确的。如果您没有设置IV,不妨指定ECB模式,记住ECB不是很安全。否则,如果要保持CBC模式,请在解密每个新文件之前将IV重置为所有0字节。但要澄清的是,IV为所有0字节的CBC与ECB完全相同。但这只适用于文件的第一个块。在那之后,随着链接的开始,CBC模式将保护其他块。@WDS我想你知道你的意思,但你的说法是误导性的。澄清一下,拥有全部0的IV的CBC和欧洲央行不是一回事。第一个块的结果相同,但两个块之间计算的后续块不同。有关欧洲央行和CBC的图片,请参见。@Russchultz您介意解释一下我的陈述有何误导性吗?特别是考虑到你的陈述用略微不同的词表达了完全相同的东西。至于Wikipedia链接,如果它是为我准备的,我向你保证我知道CBC模式是什么以及如何实现它,即使你不满意我在评论框狭窄的空间中对它的解释。@WDS你的第一句话(“带IV的所有0字节的CBC与ECB完全相同”),单独使用时是不正确的。算法是不同的。这与第一条评论(“如果你没有设置IV,不妨指定ECB模式”)一起,单独来看,这也是事实上错误的,这会导致不熟悉的人走上错误的理解道路。